Spring获取某注解下的所有类(bean),前提是该类在是spring容器进行了注册。Spring获取注解为null

Spring获取某注解下的所有类(bean),前提是该类在是spring容器进行了注册。Spring获取注解为null

注解类NettyHandler

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NettyHandler {
    String name();
    int order();
}

无法获取注解NettyHandler

监听Application,在项目准备就绪时获取被@NettyHandler注释的beans,再通过bean获取@NettyHandler的信息

import xxx.annotation.NettyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import java.util.Map;

@Slf4j
@Component
public class AnnotationListener implements ApplicationListener<ApplicationReadyEvent> {
   
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("=============" + event.getApplicationContext());
        Map<String, Object> beansWithAnnotation = event.getApplicationContext().getBeansWithAnnotation(NettyHandler.class);

        for (Object value : beansWithAnnotation.values()) {
            NettyHandler nettyHandler = value.getClass().getAnnotation(NettyHandler.class);
            if (nettyHandler == null) {
                log.error("NettyHandler is Null");
            } else {
                log.info("NettyHandler is not Null");
            }
        }
    }
}

通过日志可知,该listener会被执行两次:
第一次在event.getApplicationContext()为对象org.springframework.context.annotation.AnnotationConfigApplicationContext。
第二次在event.getApplicationContext()为对象org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext。
只有第二次event.getApplicationContext().getBeansWithAnnotation(NettyHandler.class)才获取到数据,打印信息如下:

2020-04-24 08:45:39,623 | INFO | TraceId: | NettyHandler is not Null
2020-04-24 08:45:39,623 | INFO | TraceId: | NettyHandler is not Null
2020-04-24 08:45:39,630 | ERROR | TraceId: | NettyHandler is Null
2020-04-24 08:45:39,636 | ERROR | TraceId: | NettyHandler is Null
2020-04-24 08:45:39,642 | ERROR | TraceId: | NettyHandler is Null

问题分析

经对比能获取到注解的bean和没有获取的注解的bean的信息,发现两个bean存在差异,没有获取到注解信息的bean中有如下信息:
在这里插入图片描述
由此可见,改bean是Spring通过CGLIB生成的代理对象,不是原始对象,因此无法通过代理对象的Class信息获取注解信息。检查对象的java代码,发现是使用了注解@Async,去掉@Async注解后,bean对象可以获取到注解信息了。
但,如果一定要在bean对象中放入类似于@Async的注解,或其他代表切面的信息,该怎么办呢?可以按照如下代码处理。

解决方案

import xxx.annotation.NettyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.Map;

@Slf4j
@Component
public class AnnotationListener implements ApplicationListener<ApplicationReadyEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("=============" + event.getApplicationContext());
        Map<String, Object> beansWithAnnotation = event.getApplicationContext().getBeansWithAnnotation(NettyHandler.class);

        //方法一:无法获取代理类的注解
        for (Object value : beansWithAnnotation.values()) {
            NettyHandler nettyHandler = AnnotationUtils.getAnnotation(value.getClass(), NettyHandler.class);
            if (nettyHandler == null) {
                log.error("NettyHandler is Null");
            } else {
                log.info("NettyHandler is not Nul");
            }
        }

        //方法二:可以获取代理类和非代理类的注解
        for (String beanName : beansWithAnnotation.keySet()) {
            ConfigurableListableBeanFactory clbf = event.getApplicationContext().getBeanFactory();
            Object value = clbf.getSingleton(beanName);
            if (value != null) {
                NettyHandler nettyHandler = AnnotationUtils.findAnnotation(value.getClass(), NettyHandler.class);
                if (nettyHandler == null) {
                    log.error("beanFactroy: NettyHandler is Null");
                } else {
                    log.info("beanFactroy: NettyHandler is not Nul");
                }
            }
        }

        //方法三:可以获取代理类的注解
        try {
            for (Object value : beansWithAnnotation.values()) {
                //仅适用于代理类
                NettyHandler nettyHandler = Class.forName(value.getClass().getGenericSuperclass().getTypeName()).getAnnotation(NettyHandler.class);
                if (nettyHandler == null) {
                    log.error("Class.forName: NettyHandler is Null");
                } else {
                    log.info("Class.forName: NettyHandler is not Nul");
                }
            }
        }catch (ClassNotFoundException e) {
                e.printStackTrace();
        }
    }

日志信息

2020-04-24 10:49:35,158 | INFO | TraceId: | NettyHandler is not Nul
2020-04-24 10:49:35,159 | INFO | TraceId: | NettyHandler is not Nul
2020-04-24 10:49:35,159 | ERROR | TraceId: | NettyHandler is Null
2020-04-24 10:49:35,160 | ERROR | TraceId: | NettyHandler is Null
2020-04-24 10:49:35,160 | ERROR | TraceId: | NettyHandler is Null
2020-04-24 10:49:35,161 | INFO | TraceId: | beanFactroy: NettyHandler is not Nul
2020-04-24 10:49:35,161 | INFO | TraceId: | beanFactroy: NettyHandler is not Nul
2020-04-24 10:49:35,161 | INFO | TraceId: | beanFactroy: NettyHandler is not Nul
2020-04-24 10:49:35,161 | INFO | TraceId: | beanFactroy: NettyHandler is not Nul
2020-04-24 10:49:35,161 | INFO | TraceId: | beanFactroy: NettyHandler is not Nul
2020-04-24 10:49:35,162 | ERROR | TraceId: | Class.forName: NettyHandler is Null
2020-04-24 10:49:35,162 | ERROR | TraceId: | Class.forName: NettyHandler is Null
2020-04-24 10:49:35,163 | INFO | TraceId: | Class.forName: NettyHandler is not Nul
2020-04-24 10:49:35,163 | INFO | TraceId: | Class.forName: NettyHandler is not Nul
2020-04-24 10:49:35,163 | INFO | TraceId: | Class.forName: NettyHandler is not Nul

由日志可见,使用方法二更加保险。方法一只适用于非代理类,方法三只适用于代理类。

调整后代码

import xxx.annotation.NettyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.Map;

@Slf4j
@Component
public class AnnotationListener implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
    	//避免不必要的重复执行
        if (event.getApplicationContext() instanceof ConfigurableWebServerApplicationContext) {
            System.out.println("=============" + event.getApplicationContext());
            Map<String, Object> beansWithAnnotation = event.getApplicationContext().getBeansWithAnnotation(NettyHandler.class);

            //方法二:可以获取代理类和非代理类的注解
            for (String beanName : beansWithAnnotation.keySet()) {
                ConfigurableListableBeanFactory clbf = event.getApplicationContext().getBeanFactory();
                Object value = clbf.getSingleton(beanName);
                if (value != null) {
                    NettyHandler nettyHandler = AnnotationUtils.findAnnotation(value.getClass(), NettyHandler.class);
                    if (nettyHandler == null) {
                        log.error("beanFactroy: NettyHandler is Null");
                    } else {
                        log.info("beanFactroy: NettyHandler is not Nul");
                    }
                }
            }
        }
    }
}
发布了3 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qingrunhao/article/details/105726141