1 背景
在spring boot中,利用ApplicationContext扫描自定义方法注解,可能出现无法获取自定义注解的情况
通过debug得到class文件名含有EnhancerBySpringCGLIB
,类似于这样:
或含有$ProxyXXX
,类似于这样:
2 原因
其根本原因在于,applicationContext.getBeansWithAnnotation(类注解.class)
方法获取Bean时,可能拿到的是GClib代理后的类或者Jdk代理的类,导致 bean.getClass().getDeclaredMethods()
拿不到原真实类的方法
因此需要根据具体情况,判断是何种代理,然后利用反射去获取对应真实类,拿到其方法
3 案例
这里封装了一个自定义方法注解,用于监听MQ消息:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MqttListener {
/**
* TOPIC,支持处理多个消息
*
* @return
*/
String[] value() default {};
/**
* QOS
*
* @return
*/
int qos() default 0;
}
将注解添加到对应的方法上
@MqttListener(Topic.TEST)
public void test(MqttEntity entity) {
log.info("接收到的数据:{}", entity);
testSync(entity.getValues());
}
在项目中新增一个配置类实现CommandLineRunner
,实现其run方法,通过ApplicationContext
扫描程序中的bean,拿到对应的注解
@Component
@Slf4j
public class MqttAnnotationScanner implements CommandLineRunner {
@Autowired
private ApplicationContext applicationContext;
@Override
public void run(String... args) throws Exception {
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(beanName -> {
Object bean = applicationContext.getBean(beanName);
Method[] declaredMethods = null;
//判断是何种类型的代理
if (AopUtils.isJdkDynamicProxy(bean)){
Object singletonTarget = AopProxyUtils.getSingletonTarget(bean);
if (singletonTarget != null) {
declaredMethods = singletonTarget.getClass().getDeclaredMethods();
}
} else if (AopUtils.isCglibProxy(bean)) {
declaredMethods = bean.getClass().getSuperclass().getDeclaredMethods();
} else {
declaredMethods = bean.getClass().getDeclaredMethods();
}
if (declaredMethods != null) {
for (Method method : declaredMethods) {
MqttListener annotation = method.getAnnotation(MqttListener.class);
if (annotation != null) {
// ......执行相应的逻辑
}
}
}
});
}
}
通过这种方式既可解决自定义注解扫描失败的问题,同时自定义注解还可与其他注解实现共存