结论:如果一个对象要被生成代理,那么不要对它的属性或方法进行注入,这些都会变成null(构造器注入是可以的)
首先第一个问题:
如果循环引用的对象需要被拦截,即要创建代理怎么办?
假如A依赖B,B依赖A,(A有一个属性B b,B有一个属性A a)且A需要被aop拦截,需要创建代理去替代本身:
假如首先创建A,先用构造方法创建了一个A的早期实例,把它放在singletonFactories中,然后调用populateBean去给它填充属性时,发现需要创建B,然后去进入创建B的流程,在创建完B实例后,须去填充B的a属性
applyPropertyValues
->resolveValueIfNecessary(BeanDefinitionValueResolver)尝试去获取a的实例,已经有实例了,但在去获取的过程中,会发现a是一个factorybean,此时要去检查是否需要对它生成代理,发现需要,则生成代理后放入二级缓存,并从三级缓存中删除原始实例,填充到B的属性中。接着去完成B的创建
B创建完后,回到A的创建流程,把这个创建完成的B填充到A的属性b,然后会检查A是不是有早期引用(检查二级和三级缓存),发现有(即是那个代理对象),然后用代理对象把A给代替了放入容器中,但此时这个代理对象的属性是没有B的引用的!
在mvc中验证,此时调用A的b属性,得到的是空
接下来是两个例子,分别是循环引用和非循环引用的场景;
首先是两个bean类:
测试代码:
在不使用代理时:
输出:
aop1:com.ljy.inspector.aop.Aop1Util@1fe8f5e8
aop2:com.ljy.inspector.aop.Aop2Util@2e0ad709
1.2= com.ljy.inspector.aop.Aop2Util@2e0ad709
2.1= com.ljy.inspector.aop.Aop1Util@1fe8f5e8
添加切面:(即会对aop1util 创建代理)
再执行测试代码:
aop1:com.ljy.inspector.aop.Aop1Util@56b1e527
aop2:com.ljy.inspector.aop.Aop2Util@6b25ef1c
1.2= null
2.1= com.ljy.inspector.aop.Aop1Util@56b1e527
如果出现了循环引用,原始对象并不会把自己已经创建好的属性赋给用来替代它的那个代理对象.
那么如果不循环引用的话呢?我们知道,正常给一个对象创建代理是在
initializeBean()->applyBeanPostProcessorsAfterInitialization()中,也就是后置处理中。
经过验证,就算不循环引用,前期的创建的属性在创建了代理后仍会被清空。
对于两个工具类:
测试代码:
结果:
aop1:com.ljy.inspector.aop.Aop1Util@56b1e527
aop2:com.ljy.inspector.aop.Aop2Util@4e974b9e
1.2= null
可以进入堆栈中看:
在创建aop1util时,当执行完populateBean时,它的“aop2Util”属性就已经被填充了,此时它仍是正常的实例
在进入initialzeBean后,执行完前置处理后,可以看到这个bean仍然没有变化:(在initialzeBean中以wrappedBean为准)
但一经过后置处理,可以看到wrappedBean已经变成了代理对象,而且其aop2util属性是空
结论:如果一个对象要被生成代理,那么不要对它的属性或方法进行注入,这些都会变成null(构造器注入是可以的,因为构造器注入时创建代理对象时必须要调用其父类(也就是被代理类)的构造函数,此时就会把要注入的对象注入了)