一、什么是循环依赖
首先,我们设想有这么一个场景,有TestA、TestB、TestC三个类,TestA依赖注入TestB,TestB依赖注入TestC,TestC又依赖注入TestA,在实例化Bean时就会构成了循环依赖。
当我们希望向一个Bean里注入另外一个Bean时,
通常有两种方式:
(1)构造器注入
(2)setter()注入
那么相应的Spring的循环依赖也包含了两种情况:
(1)构造器循环依赖
(2) setter方法循环依赖,其中又分为单例循环依赖和多例循环依赖
然后,我们要介绍另外一个名词,“当前创建Bean池”,这是在Spring中用于存放正在创建的Bean的数据结构,用于检查循环依赖的。
二、构造器循环依赖
首先它是无法被解决的,Spring中出现了这种构造器循环依赖的处理方式就是报错。
为什么无法解决呢?我们推演一下TestA,TestB,TestC的创建流程。
2、创建TestB,首先去“当前创建Bean池”中查找是否存在TestB的标识符,没有找到,通过构造方法创建对象,发现构造方法需要TestC作为参数,创建TestC,并且把TestB的标识符放入“当前创建Bean池”。
4、创建TestA,首先去“当前创建Bean池”中查找是否存在TestA的标识符,卧槽,找到了,有循环依赖,报错。
三、单例setter循环依赖
这种循环依赖是可以被解决的。Spring的解决方式就是在初始化Bean的时候,通过ObjectFactory工厂单例方法提前曝光已经创建但是还没设置属性的Bean。同样是上述的例子。
2、创建TestB,首先去“当前创建Bean池”中查找是否存在TestB的标识符,没有找到,通过无参构造方法创建实例,通过ObjectFactory提前曝光正在创建的TestB,把TestB标识符放入“当前创建Bean池”,通过setter方法注入TestC,调用getBean()获取TestC实例,由于还没创建,创建TestC。
4、由于TestC已经完成属性注入创建完毕,TestB也可以成功注入TestC,TestA也可以成功注入TestB,至此TestA,TestB,TestC创建完毕。