Spring 代理 Bean 中获取不到原始 Bean 对象注解的解决方法

简介: 我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试。所以我需要对 consumer 对象进行代理,然后如果超过异常次数,我直接返回成功,并且发送成功消息,但是我获取 consumer handler 方法的方式是通过 method.getAnnotation(XXClient.class) 方式,那么就会返回 null。

问题描述


我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试。 所以我需要对 consumer 对象进行代理,然后如果超过异常次数,我直接返回成功,并且发送成功消息,但是我获取 consumer handler 方法的方式是通过 method.getAnnotation(XXClient.class) 方式,那么就会返回 null。


问题示例代码


  1. 目标类, 我这里就之定义一个 test 方法,里面做一些个简单的打印。


@Component
public class TestBean {
    @Anno
    public void test() {
        System.out.println("test .....");
    }
}


  1. 代理逻辑逻辑处理, 主要就是做一个 @Around 的方法覆盖,保证在调用目标方法之前,先输出我插入的逻辑。


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno {
    String key() default "100%";
}
@Aspect
@Component
public class AnnoAspect {
    @Around("@annotation(anno)")
    public Object anno(ProceedingJoinPoint point, Anno anno) throws Throwable {
        System.out.println("anno invoke!!!!!!");
        return point.proceed();
    }
}


  1. 调用点, 通过 AnnotationConfigApplicationContext 获取 bean. 然后通过 getMethods() 获取所有的方法,最后查找 Anno 注解的 Method 对象。


AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanStart.class);
    TestBean bean = applicationContext.getBean(TestBean.class);
    Class<? extends TestBean> classz = bean.getClass();
    Method[] methods = classz.getMethods();
    for (Method m : methods) {
        Anno annotation = m.getAnnotation(Anno.class);
        if (annotation != null) {
            System.out.println(" ============= invoke test ===========");
            m.invoke(bean, new Object());
        }
    }    


由于 m.getAnnotaion(Anno.class) 无法获取到注解信息,所以执行 test 方法失败, 到此问题还原完毕,我们再来看看如何解决。


解决方案


通过 Anno ao = AnnotationUtils.findAnnotation(method, Anno.class); 方法获取即可。


有的代码是这样写的 :


String name = classz.getName();
boolean isSpringProxy = name.indexOf("SpringCGLIB$$") >= 0;
Method[] methods;
if (isSpringProxy) {
    methods = ReflectionUtils.getAllDeclaredMethods(AopUtils.getTargetClass(bean));
} else {
    methods = classz.getMethods();
}
// 省略部分代码
if (isSpringProxy) {
    annotation = AnnotationUtils.findAnnotation(method, MqClient.class);
} else {
    annotation = method.getAnnotation(Anno.class);
}


这里他会做一个判断,如果是代理对象就调用  

ReflectionUtils.getAllDeclaredMethods 获取所有的方法, 然后再去拿注解的时候二次判断一下,如果存在代理,那么就通过 AnnotationUtils.findAnnotation 感觉是相当的严谨。


总结:Spring 提供了非常强大的一站式开发功能,而且还提供了比较优秀的工具方法比如: BeanUtilsReflectionUtilsAnnotationUtils 等,这些都是我们值得掌握的基础工具类。


参考资料



相关文章
|
4天前
|
Java 开发者 Spring
深入理解Spring Boot的@ComponentScan注解
【4月更文挑战第22天】在构建 Spring Boot 应用时,@ComponentScan 是一个不可或缺的工具,它使得组件发现变得自动化和高效。这篇博客将详细介绍 @ComponentScan 的基本概念、关键属性及其在实际开发中的应用。
21 4
|
6天前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
29 6
|
24天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
32 1
|
1天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
17 1
|
13天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
13天前
|
XML Java 数据格式
进阶注解探秘:深入Spring高级注解的精髓与实际运用
进阶注解探秘:深入Spring高级注解的精髓与实际运用
26 2
|
13天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
30 2
从入门到精通:Spring基础注解的全面解析
|
13天前
|
Java Spring
玩转对象掌控权:深入Spring,精准控制对象创建次数
玩转对象掌控权:深入Spring,精准控制对象创建次数
16 0
|
13天前
|
Java 关系型数据库 MySQL
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
27 0
高级对象装配:解析Spring创建复杂对象的秘诀