Spring代理对象导致的获取不到原生对象注解的解决

目录
  • 问题描述
  • 问题示例代码
  • 解决方案
  • 总结
  • 参考资料

问题描述

我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试。

所以我需要对 consumer 对象进行代理,然后如果超过异常次数,我直接返回成功,并且发送成功消息,但是我获取 consumer handler 方法的方式是通过 method.getAnnotation(XXClient.class) 方式,那么就会返回 null。

问题示例代码

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

@Component
public class TestBean {

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

代理逻辑逻辑处理, 主要就是做一个 @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();
    }

}

调用点, 通过 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(classz, 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 提供了非常强大的一站式开发功能,而且还提供了比较优秀的工具方法比如: BeanUtils 、ReflectionUtils 、AnnotationUtils 等,这些都是我们值得掌握的基础工具类。

参考资料

https://www.jianshu.com/p/b69e64121b97

到此这篇关于Spring代理对象导致的获取不到原生对象注解的解决的文章就介绍到这了,更多相关Spring获取不到原生对象注解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring代理对象导致的获取不到原生对象注解的解决

    目录 问题描述 问题示例代码 解决方案 总结 参考资料 问题描述 我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试. 所以我需要对 consumer 对象进行代理,然后如果超过异常次数,我直接返回成功,并且发送成功消息,但是我获取 consumer handler 方法的方式是通过 method.getAnnotation(XXClient.class) 方式,那么就会返回 null. 问题示例代码 目标类, 我这里就之定义一个 test 方法,

  • 如何获得spring代理对象的原对象

    获得spring代理对象的原对象 看代码吧: @SuppressWarnings({"unchecked"}) protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception { if (AopUtils.isJdkDynamicProxy(proxy)) { return (T) ((Advised)proxy).getTargetSource().get

  • Java 如何从spring容器中获取注入的bean对象

    1.使用场景 控制层调用业务层时,控制层需要拿到业务层在spring容器中注入的对象 2.代码实现 import org.apache.struts2.ServletActionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.suppo

  • 如何在Spring WebFlux的任何地方获取Request对象

    1 不一样的世界 在常规的Spring Web项目中,我们要获取Request对象是非常方便的,不少库都提供了静态方法来获取.获取代码如下: ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); // get the request HttpServletRequest request = requestAttribut

  • Spring处理@Async导致的循环依赖失败问题的方案详解

    目录 简介 问题复现 原因分析 解决方案 方案1:懒加载 方案2:不让@Async的类有循环依赖 方案3:allowRawInjectionDespiteWrapping设置为true 为什么@Transactional不会导致失败 简介 说明 本文介绍SpringBoot中的@Async导致循环依赖失败的原因及其解决方案. 概述 我们知道,Spring解决了循环依赖问题,但Spring的异步(@Async)会使得循环依赖失败.本文将用实例来介绍其原因和解决方案. 问题复现 启动类 启动类添加@

  • 这一次搞懂Spring代理创建及AOP链式调用过程操作

    前言 AOP,也就是面向切面编程,它可以将公共的代码抽离出来,动态的织入到目标类.目标方法中,大大提高我们编程的效率,也使程序变得更加优雅.如事务.操作日志等都可以使用AOP实现.这种织入可以是在运行期动态生成代理对象实现,也可以在编译期.类加载时期静态织入到代码中.而Spring正是通过第一种方法实现,且在代理类的生成上也有两种方式:JDK Proxy和CGLIB,默认当类实现了接口时使用前者,否则使用后者:另外Spring AOP只能实现对方法的增强. 正文 基本概念 AOP的术语很多,虽然

  • 关于Spring的@Transaction导致数据库回滚全部生效问题(又删库跑路)

    1 前言 很多需要使用事务的场景,都只是在方法上直接添加个@Transactional注解 但是,你以为这真的够了吗? 事务如果未达到完美效果,在开发和测试阶段都难以被发现,因为你难以考虑到太多意外场景.但当业务数据量发展,就可能导致大量数据不一致的问题,就会造成前人栽树后人踩坑,需要大量人力排查解决问题和修复数据. 2 如何确认Spring事务生效了? 使用@Transactional一键开启声明式事务, 这就真的事务生效了?过于信任框架总有"意外惊喜".来看如下案例 领域层 实体

  • Spring Aop 源码增强获取分享

    目录 1 前言 2 spring 增强器 3 总结 1 前言 在前文中,已经讲述了 AOP的后置处理器使用和方法,在本文中继续分享增强信息相关的源码,这里才是 AOP 的核心代码. 2 spring 增强器 之前已经讲述了 spring AbstractApplicationContext.refresh 方法,在以下方法中都会处理会处理 BeanPostProcessor 接口. invokeBeanFactoryPostProcessors registerBeanPostProcessor

  • Spring实现Aware接口自定义获取bean的两种方式

    在使用spring编程时,常常会遇到想根据bean的名称来获取相应的bean对象,这时候,就可以通过实现BeanFactoryAware来满足需求,代码很简单: @Servicepublic class BeanFactoryHelper implements BeanFactoryAware { private static BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory

  • 通过Spring Security魔幻山谷讲解获取认证机制核心原理

    本文基于Springboot+Vue+Spring Security框架而写的原创学习笔记,demo代码参考<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>一书. 这是一个古老的传说. 在神秘的Web系统世界里,有一座名为SpringSecurity的山谷,它高耸入云,蔓延千里,鸟飞不过,兽攀不了.这座山谷只有一条逼仄的道路可通.然而,若要通过这条道路前往另一头的世界,就必须先拿到一块名为token的令牌,只有这样,道路上戍守关口

随机推荐