springboot实现自定义回调方法注解

一直很羡慕kafka的@KafkaListener注解,在方法上加上这个注解就可以自动监听消息,非常方便且灵活。但有些工具缺没有封装此类注解,例如netty、redis队列等,于是就自己整了个。

思路非常简单,获取spring ioc容器所有bean,然后进行匹配自定义注解,最后利用反射机制代理方法即可。

废话少说,直接上码。

首先,增加spring bean工具类。

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;
    }

}

添加自定义注解类

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 {


}

在入口处代理回调含有自定义注解的方法


    /**
     * 接收消息
     * @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);
    }

在监听器类添加监听方法

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());
    }
    
}

猜你喜欢

转载自blog.csdn.net/zdb1314/article/details/129116540