本文共 2710 字,大约阅读时间需要 9 分钟。
一、场景
对于Spring中的循环场景(具体可前往查看):
仅仅只需要加个map就可以了。
@Component("aService")public class AService(){ @Autowired private BService bService; public void xxx(){ }}
@Component("bService")public class BService(){ @Autowired private AService aService; public void xxx(){ }}
生命周期简要如下:
- 实例化…AService对象(new AService())
- 填充bService属性—>从单例池中找bService—>找不到—>创建bService bService的生命周期 2.1 实例化…BService对象(new BService()) 2.2 填充aService属性—>从单例池中找aService—>找不到—>创建aService aService的生命周期 3.1 实例化…AService对象(new AService()) … … … 2.3 填充他属性 2.4 做其他事情 2.5 放入单例池
- 填充他属性
- 做其他事情
- 放入单例池
二、增加一个map
2.1 可以解决的问题
比如说:增加了一个map:springMap(自己临时取的名字),那么这个map有什么用?
有了map之后,生命周期会走以下流程,打破了原有的无限循环。
- 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
- 填充bService属性—>从单例池中找bService—>找不到—>创建bService bService的生命周期 2.1 实例化…BService对象(new BService())—>放入springMap<bSerivce,BService对象> 2.2 填充aService属性—>从单例池中找aService—>找不到—>从springMap中去找(找到的其实就是在第一步中放入的对象) 2.3 填充他属性 2.4 做其他事情 2.5 放入单例池
- 填充他属性
- 做其他事情
- 放入单例池
2.2 存在的问题
2.1.1 不完整对象赋值属性?
在第一步,aService实例化得到一个对象,此时对象中的属性是没有值的。
在第二步,2.2步骤中拿到的aService对象也是没有值的。
其实简单来说:
A a = new A();
B b = new B();
b.a = a;
a.b = b;
属性暂时没有值的对象称之为不完整的Bean对象。
虽然在第二步的时候把一个不完整的AService对象赋给了a属性,但在最后的时候会给对应对象的属性赋上值,因为从始至终都是用的一个AService对象,所以总的来说是没有问题的。
2.1.2 对象不一致
- 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
- 填充bService属性—>从单例池中找bService—>找不到—>创建bService bService的生命周期 2.1 实例化…BService对象(new BService())—>放入springMap<bSerivce,BService对象> 2.2 填充aService属性—>从单例池中找aService—>找不到—>从springMap中去找(找到的其实就是在第一步中放入的对象) 2.3 填充他属性 2.4 做其他事情 2.5 放入单例池
- 填充他属性
- 做其他事情
- 放入单例池
可以看到,第四步是做其他的事。
那么,如果这里是AOP,Spring会生成一个AService的代理对象。
加上第一步实例化的对象会有两个,
最终在第五步放入单例池的应该是第四步的代理对象。
第2.2步中,填充的a属性也会是代理对象
但是如果从springMap中获取,取到的是第一步实例化的AService对象。
这个就是问题所在。
2.3 处理对象不一致
那么怎样才可以使得有AOP时,可以使得所有地方使用的都是代理对象?
2.3.1 思路:提前进行AOP
填充属性是在2.2,而AOP是在4。
正常情况下AOP就是在第四步执行的,但是循环依赖是一种特殊情况,
Spring对特殊情况进行处理,会把AOP提前,因为在2.2的时候就需要一个AService代理对象。
所以在第一步实例化的时候,判断是否需要AOP,如果需要,优先进行AOP,得到代理对象,放入SpringMap中,后续使用的一直是这个代理对象。
注意:只有AService出现了循环依赖的情况,才会对AService提前进行AOP。正常情况下还是在第四步进行执行。
2.3.2 如何判断出循环依赖
上述说将AOP提前,由于存在循环依赖的条件,所以要先判断,那么在第一步时候如何判断出现了循环依赖呢?
可以很明显的看出,第一步是很难判断出来的,那么就需要找到合适的位置。
最终定位在 2.2。
我们可以在第一步之前初始化一个set,用来存放正在创建的Bean对象,比如:creatingSet。
然后在2.2中判断所需要的AService是否在creatingSet中,并且ASerivce是需要AOP的,那么就在此处进行AOP,得到对象之后,放入SpringMap中,
最终的生命周期如下:
0. creatingSet
- 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
- 填充bService属性—>从单例池中找bService—>找不到—>创建bService bService的生命周期 2.1 实例化…BService对象(new BService())—>放入springMap<bSerivce,BService对象> 2.2 填充aService属性—>从单例池中找aService—>找不到—>判断aService正在创建中(则证明出现了循环依赖)&&需要AOP—>提前AOP—>得到代理对象—>放入springMap<aSerivce,AService对象> 2.3 填充他属性 2.4 做其他事情 2.5 放入单例池
- 填充他属性
- 做其他事情
- 放入单例池
- creatingSet.remove(“aService”)
转载地址:http://aayai.baihongyu.com/