通过spring容器中的代理对象获取目标对象

Posted 八阿哥克星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过spring容器中的代理对象获取目标对象相关的知识,希望对你有一定的参考价值。

一般情况下,在springboot项目中被IOC容器管理的类在创建对象时,会经过aop的后置处理器(BeanPostProcessor)生成代理对象供我们使用,那如果想要获取目标对象怎么做呢,通常用到AopUtils工具类```

public Object test(Object proxy) throws Exception 
        //判断是否是代理对象
        if(AopUtils.isAopProxy(proxy))
            //cglib 代理
            if(AopUtils.isCglibProxy(proxy))
                //通过暴力反射拿到代理对象的拦截器属性,从拦截器获取目标对象
                Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
                h.setAccessible(true);
                Object dynamicAdvisedInterceptor = h.get(proxy);

                Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
                advised.setAccessible(true);
                Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
                //返回目标对象
                return target;
            
            //jdk代理
            if(AopUtils.isJdkDynamicProxy(proxy))
                //通过暴力反射拿到代理对象的拦截器属性,从拦截器获取目标对象
                Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
                h.setAccessible(true);
                AopProxy aopProxy = (AopProxy) h.get(proxy);

                Field advised = aopProxy.getClass().getDeclaredField("advised");
                advised.setAccessible(true);

                Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();

                return target;
            
        
        return null;

    


```

但是,这样做有一个前提,就是aop的后置处理器起作用生成了代理对象

如果,我想获取某个@Configuration注解的配置类对象的原生目标对象怎么办,上述方法还管用吗?我最近就遇到过这个问题,要通过某个配置类的class通过反射拿到其某个属性,于是按照上述步骤运行,结果大跌眼镜,AopUtils.isAopProxy(proxy)的值居然是false,也就有了我上面标黑的叙述。

已知@Configuration注解的配置类是cglib代理对象,但是却不是aop后置处理器生成的,那么,他的代理对象是怎么生成的?首先,cglib代理是用ASM字节码技术对class文件修改进而完成对目标类的增强的,所以只需要知道配置类的lass文件何处被修改或者替换的。就在spring启动流程中的:

 

这里,会解析所有配置类,并把class替换成代理类的class,后来getBean获取对象用的就是代理类的class了。具体的代码位置是在ConfigurationClassPostProcessor#enhanceConfigurationClasses

 

以上是关于通过spring容器中的代理对象获取目标对象的主要内容,如果未能解决你的问题,请参考以下文章

通过spring容器中的代理对象获取目标对象

arthas 获取spring被代理的目标对象

spring aop获取代理目标对象

面试官:Spring代理目标bean时为何通过TargetSource类型对目标bean封装?

面试官:Spring代理目标bean时为何通过TargetSource类型对目标bean封装?

面试官:Spring代理目标bean时为何通过TargetSource类型对目标bean封装?