spring的循环依赖

A需要依赖B,B也需要依赖A的情况就是循环依赖。

Spring通过三级缓存的机制来解决循环依赖,其中一级缓存存放的是完全初始化好的Bean,二级缓存存放的是实例化好但没有初始化的Bean,三级缓存存放的是Bean工厂。

创建AB的过程如下:

1.开始创建A:

  • 此时缓存中没有A,Spring调用A的构造方法,A的实例已存在但B的属性为空。
  • 将A的工厂放入三级缓存,开始对A进行属性注入。
    2.开始对A进行属性注入:
  • 注入的过程中发现需要B,于是开始创建B,Spring调用B的构造方法。
  • 创建好B的实例后A的属性还是空,于是将B的工厂放入三级缓存开始对B进行属性注入。
    3.B需要注入A,完成属性注入:
  • B需要注入A,于是先在一级缓存中查找,一级缓存中没有再从二级缓存中找,二级缓存也没有最后在三级缓存中找到A的工厂。
  • 调用A的工厂得到A的实例,这是只有实例化的A还没有初始化,将A从三级缓存调到二级缓存中。B拿到A的引用完成属性注入。
  • B属性注入完成,从三级缓存移除放入一级缓存。
    4.初始化A:
  • 接着继续对A进行属性注入,此时已经有了初始化完成的B,完成属性注入,初始化完成,创建完成。
  • A从二级缓存移除,放入一级缓存中。
    这就是AB创建的过程。

三种Spring无法解决循环依赖的情况:

1:使用构造器注入

使用构造器注入Spring会直接抛出异常,因为构造器方法注入必须发生在实例化阶段,创建A的前提是有B,创建B的前提是有A,但此时两个都没有创建出来,所以会失败。

2:prototype作用域中的循环依赖:

prototype作用域中的Bean每次都会创建新的实例,Spring无法缓存这些实例,所以无法解决循环依赖。

3:(AB相互依赖)B中注入A的方式为setter方法,A中注入B的方式为给构造器:

Spring创建Bean的过程是按顺序执行的,所以会先创建A再创建B,创建A的时候需要B的实例,但此时缓存中还没有A,所以也无法创建B,所以无法解决。