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,所以无法解决。