Springboot implements custom callback method annotations

I have always been envious of kafka's @KafkaListener annotation. Adding this annotation to the method can automatically monitor messages, which is very convenient and flexible. However, some tools lack the ability to encapsulate such annotations, such as netty, redis queues, etc., so they made one by themselves.

The idea is very simple, get all the beans of the spring ioc container, then match the custom annotations, and finally use the reflection mechanism to proxy the method.

Cut the nonsense and go straight to the code.

First, increase the spring bean tool class.

package per.zdb.td.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextUtil.applicationContext = applicationContext;
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    /**
     * 通过方法注解代理执行方法
     * @param annotation
     * @param args
     * @return 返回成功执行的数量
     */
    public static int invokeMethodByAnnotation(Class<? extends Annotation> annotation,
                                                   Object... args) {
        int successCount = 0;
        List<Object> beans = getBeansByMethodAnnotation(annotation);

        for (Object bean : beans) {
            List<Method> methods = getMethodsByAnnotation(bean, annotation);
            for (Method method : methods) {
                try {
                    method.invoke(bean,args);
                    successCount++;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

        return successCount;
    }

    /**
     * 通过注解获取bean
     * @param annotation
     * @return
     */
    public static List<Object> getBeansByMethodAnnotation(Class<? extends Annotation> annotation) {
        List<Object> list = new ArrayList();
        String[] beanNames = getApplicationContext().getBeanDefinitionNames();

        for (String beanName : beanNames) {
            Object bean = getBean(beanName);
            List<Method> methodsByAnnotation = getMethodsByAnnotation(bean, annotation);

            if (methodsByAnnotation.isEmpty()){
                //方法未匹配则跳过
                continue;
            }

            list.add(bean);
        }

        return list;
    }

    /**
     * 通过注解获取方法
     * @param bean
     * @param annotation
     * @return
     */
    private static  List<Method> getMethodsByAnnotation(Object bean, Class<? extends Annotation> annotation) {
        List<Method> methodList = new ArrayList<>();
        Method[] methods = bean.getClass().getMethods();

        if (methods==null){
            return methodList;
        }

        for (Method item : methods) {
            Annotation annotation1 = item.getAnnotation(annotation);
            if (annotation1!=null) {
                methodList.add(item);
            }
        }

        return methodList;
    }

}

Add custom annotation class

package per.zdb.td.netty.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 接受socket消息
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SocketListener {


}

The proxy callback method with custom annotations at the entry


    /**
     * 接收消息
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        System.out.println("接收到消息:"+text);
        //执行所有@SocketListener方法
        SpringContextUtil.invokeMethodByAnnotation(SocketListener.class,ctx,msg);
    }

Add a listener method to the listener class

package per.zdb.td.netty.listener;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.stereotype.Component;
import per.zdb.td.netty.annotation.SocketListener;

@Component
public class WebSocketListener {

    @SocketListener
    public void listener(ChannelHandlerContext ctx, TextWebSocketFrame msg){
        System.out.println("1号 @SocketListener接收到消息:"+msg.text());
    }

    @SocketListener
    public void listener2(ChannelHandlerContext ctx, TextWebSocketFrame msg){
        System.out.println("2号 @SocketListener接收到消息:"+msg.text());
    }
    
}

Guess you like

Origin blog.csdn.net/zdb1314/article/details/129116540