通过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代理目标bean时为何通过TargetSource类型对目标bean封装?