CGLIB动态代理后注解无法获取
今天在开发中,使用了Srping的cglib,偶尔发现若开启CGLIB代理 spring.aop.proxy-target-class=true注入接口后无法获取其实现类上注解@service。
通过debug得到class文件名含有EnhancerBySpringCGLIB:
com.xxx.service.impl.xxxxImpl$$EnhancerBySpringCGLIB$$f69341ff
并clazz.getAnnotation();得到注解为空。
原因浅析
我们首先来看看 @Inherited:
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 也就是说如果没有@Inherited,该注解将不会用于子class。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation, 方法并不从它所实现的方法继承annotation。
另外, 当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
cglib的enhancer 为我们生成了一个在xxxxImpl的基础上的增强类,class在实际运行时候的Class对象已经不是原本的class了,又因为@service没有被@Inherited修饰,所以注解丢失了。
解决办法:
- 将spring.aop.proxy-target-class=true 去掉, 自动使用JDK代理。
- 使用 org.springframework.core.annotation.AnnotationUtils;
AnnotationUtils.getAnnotation(),但是有个缺陷是此方法只能获取类及方法上的注解,无法获取属性成员的注解。 - 使用@Inherited的方式(由于没有尝试过不清楚可行性,仅贴链接供参考):
https://www.cnblogs.com/hujunzheng/p/8433980.html