博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring循环依赖过程解析
阅读量:4170 次
发布时间:2019-05-26

本文共 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(){
}}

生命周期简要如下:

  1. 实例化…AService对象(new AService())
  2. 填充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 放入单例池
  3. 填充他属性
  4. 做其他事情
  5. 放入单例池

二、增加一个map

2.1 可以解决的问题

比如说:增加了一个map:springMap(自己临时取的名字),那么这个map有什么用?

有了map之后,生命周期会走以下流程,打破了原有的无限循环。

  1. 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
  2. 填充bService属性—>从单例池中找bService—>找不到—>创建bService
    bService的生命周期
    2.1 实例化…BService对象(new BService())—>放入springMap<bSerivce,BService对象>
    2.2 填充aService属性—>从单例池中找aService—>找不到—>从springMap中去找(找到的其实就是在第一步中放入的对象)
    2.3 填充他属性
    2.4 做其他事情
    2.5 放入单例池
  3. 填充他属性
  4. 做其他事情
  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 对象不一致

  1. 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
  2. 填充bService属性—>从单例池中找bService—>找不到—>创建bService
    bService的生命周期
    2.1 实例化…BService对象(new BService())—>放入springMap<bSerivce,BService对象>
    2.2 填充aService属性—>从单例池中找aService—>找不到—>从springMap中去找(找到的其实就是在第一步中放入的对象)
    2.3 填充他属性
    2.4 做其他事情
    2.5 放入单例池
  3. 填充他属性
  4. 做其他事情
  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

  1. 实例化…AService对象(new AService())—>放入springMap<aSerivce,AService对象>
  2. 填充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 放入单例池
  3. 填充他属性
  4. 做其他事情
  5. 放入单例池
  6. creatingSet.remove(“aService”)

转载地址:http://aayai.baihongyu.com/

你可能感兴趣的文章
SuperMap iClient3D for WebGL教程-CallbackProperty
查看>>
如何修改leaflet聚合图的层级和样式
查看>>
三维分析之开敞度分析
查看>>
BIM+GIS应用的八大挑战
查看>>
.net实现.aspx页面自动加载.cs程序定义的变量并按照格式输出
查看>>
[Leetcode]最后一个单词的长度
查看>>
merges sort use c++
查看>>
插入排序用递归实现
查看>>
工作流审批平台-审批流程-指定审批部门
查看>>
商务智能-系统概述-数据图形方式
查看>>
软件项目管理系统-项目管理-模块定义-开发内容
查看>>
工作流审批平台-审批功能
查看>>
商务智能-基本方法-特征与角度
查看>>
软件项目管理系统-项目管理-模块定义-开发笔记
查看>>
工作流审批平台-业务申请-申请书一览
查看>>
商务智能-基本方法-数据钻取
查看>>
C++程序员技术需求规划(发展方向)
查看>>
A Game of Thrones(59)
查看>>
2018.3.19
查看>>
A Game of Thrones(97)
查看>>