Spring获取方法自定义注解为null、isAnnotationPresent返回false问题
问题原因
Spring容器返回的@Repository标注类的实例默认是代理对象,并非原始业务类的实例:
- 若使用JDK动态代理:代理类仅实现对应的业务接口,重写的方法不会携带原始实现类方法上的自定义注解
- 若使用CGLIB代理:代理类是原始业务类的子类,方法级别的注解默认不会被子类继承,即使注解添加
@Inherited元注解也仅对类级别注解生效,对方法级别注解无效
解决方法
方案1:使用Spring内置工具类处理代理场景(推荐)
直接用Spring封装的AopUtils和AnnotationUtils工具类,自动适配代理场景下的注解查找逻辑,修改扫描代码如下:
import org.springframework.aop.support.AopUtils; import org.springframework.core.annotation.AnnotationUtils; @Configuration public class MyAnnotationScanner implements ApplicationContextAware { @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { for (String beanName : applicationContext.getBeanNamesForAnnotation(Repository.class)) { Object bean = applicationContext.getBean(beanName); // 获取代理对应的原始业务类 Class<?> targetClass = AopUtils.getTargetClass(bean); for (Method method : targetClass.getDeclaredMethods()) { MyAnnotation annotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class); if (annotation != null) { // 此处写入你的业务逻辑,可通过annotation.value()获取注解属性 } } } } }
方案2:注解迁移到接口方法
如果业务逻辑允许,将@MyAnnotation标注在接口Interface的doSomething方法上,代理类生成时会继承接口方法的注解,原有扫描逻辑无需修改也可以读取到注解。
方案3:手动拆解代理对象
如果不想依赖Spring的注解工具类,也可以先判断当前实例是否为代理,拆解出原始对象后再反射读取注解:
import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; if (AopUtils.isAopProxy(bean) && bean instanceof Advised) { bean = ((Advised) bean).getTargetSource().getTarget(); } // 后续再执行原有的方法注解读取逻辑即可
该方案兼容性较差,部分特殊代理场景下可能无法获取到原始对象,仅作为备选方案使用。
内容的提问来源于stack exchange,提问作者Toniotti
相关产品推荐
相关产品推荐

