Spring Boot进阶:原理、实战与面试题分析
上QQ阅读APP看书,第一时间看更新

2.3.2 循环依赖解决方案

让我们回顾2.1.3节中基于Setter方法注入的循环依赖场景,如代码清单2-21所示。

代码清单2-21 基于Setter方法注入的循环依赖代码

public class ClassA {
    private ClassB classB;

    @Autowired
    public void setClassB(ClassB classB) {
        this.classB = classB;
    }
}

public class ClassB {
    private ClassA classA;

    @Autowired
    public void setClassA(ClassA classA) {
        this.classA = classA;
    }
}

现在假设我们先初始化ClassA。ClassA首先通过createBeanInstance()方法创建了实例,并且将这个实例提前暴露到第三级缓存singletonFactories中。然后,ClassA尝试通过populateBean()方法注入属性,发现自己依赖ClassB这个属性,就会尝试去获取ClassB的实例。

显然,这时候ClassB还没有被创建,所以要走创建流程。ClassB在初始化第一步的时候发现自己依赖了ClassA,就会尝试从第一级缓存singletonObjects去获取ClassA的实例。因为ClassA这时候还没有被创建完毕,所以它在第一级缓存和第二级缓存中都不存在。当尝试访问第三级缓存时,因为ClassA已经提前暴露了,所以ClassB能够通过singletonFactories拿到ClassA对象并顺利完成所有初始化流程。

ClassB对象创建完成之后会被放到第一级缓存中,这时候ClassA就能从第一级缓存中获取ClassB的实例,进而完成ClassA的所有初始化流程。这样ClassA和ClassB都能够成功完成创建过程,整个流程如图2-3所示。

049-1

图2-3 基于Setter方法注入的循环依赖解决流程

讲到这里,相信你也理解了为什么构造器注入无法解决循环依赖问题。这是因为构造器注入过程是发生在Bean初始化的第一个步骤createBeanInstance()中,而这个步骤还没有调用addSingletonFactory()方法完成第三级缓存的构建,自然也就无法从该缓存中获取目标对象。