-
Bean的实例化过程中和循环依赖有关的代码
//1. 创建Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 针对循环依赖问题提前暴露单例工厂类
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
//2. 注入属性
populateBean(beanName, mbd, instanceWrapper);
-
循环依赖的代码:
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;
}
}
-
图2-3 基于Setter方法注入的循环依赖解决流程
现在假设我们先初始化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所示。
郑天民著《Spring Boot进阶:原理、实战与面试题分析》机械工业出版社有限公司.