Spring通过三级缓存的方式来解决循环依赖问题。三级缓存分别是:
- singletonObjects:一级缓存,用于保存实例化、注入、初始化完成的bean实例。
- earlySingletonObjects:二级缓存,用于保存实例化完成的bean实例。
- singletonFactories:三级缓存,用于保存bean创建工厂,以便于后面扩展。
下面是Spring解决循环依赖的步骤:
-
创建Bean A,首先去一级缓存中获取,如果没有则去二级缓存中获取,如果还是没有则去三级缓存中获取。如果都没有则开始创建Bean A。
-
实例化Bean A,将其放入到二级缓存中。注意此时Bean A已经实例化完成,但是还没有進行属性注入和初始化。
-
对Bean A进行属性注入时,发现依赖了Bean B,此时递归去创建Bean B。
-
创建Bean B的过程与上述类似,实例化完成后将其放入到二级缓存中。
-
对Bean B进行属性注入时,发现依赖了Bean A,此时递归去创建Bean A。
-
从二级缓存中获取到已经实例化完成的Bean A,并把它放到一级缓存中。返回Bean A的实例,继续对Bean B进行属性注入。
-
Bean B完成属性注入和初始化后,将其放入到一级缓存中,并从二级缓存和三级缓存中移除。返回Bean B的实例,继续对Bean A进行属性注入。
-
Bean A完成属性注入和初始化后,将其放入到一级缓存中,并从二级缓存和三级缓存中移除。至此,循环依赖问题解决。
关键点在于:
- 实例化Bean时就把它放入到缓存中,而不是等到完全初始化好再放入缓存。
- 每个Bean在创建过程中,都会先去缓存中查找是否已经存在,如果已经存在说明发生了循环引用,直接使用缓存中的实例而不是再去创建。
- 三级缓存的作用在于提前暴露实例的引用,如果没有三级缓存,按照上面的流程,会导致Bean B在注入Bean A时又去创建Bean A,无法终止循环。
这就是Spring解决循环依赖的核心思路。通过三级缓存提前暴露实例,并在递归时检查缓存而不是重复创建实例,从而解决了循环依赖的问题。
举例说明:
以下代码基于Spring 5.2.8版本的AbstractAutowireCapableBeanFactory
类:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1. 实例化Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 2. 将实例化后的Bean放入到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 3. 对Bean进行属性注入
populateBean(beanName, mbd, instanceWrapper);
// 4. 对Bean进行初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
if (earlySingletonExposure) {
// 5. 从三级缓存中获取Bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
return exposedObject;
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 先从一级缓存中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存中没有,并且当前Bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 2. 从二级缓存中获取Bean
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// 3. 从三级缓存中获取Bean
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将Bean工厂放入到三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
}
主要步骤:
- 在
doCreateBean
方法中,首先实例化Bean。 - 如果允许循环引用,则将实例化后的Bean包装成
ObjectFactory
放入到三级缓存singletonFactories
中。 - 对Bean进行属性注入,如果发现依赖了其他Bean,则递归去创建其他Bean。
- 对Bean进行初始化。
- 如果允许循环引用,则尝试从三级缓存
singletonFactories
中获取Bean。因为在第2步中已经将Bean放入到三级缓存中了,所以这里可以获取到。
在getSingleton
方法中:
- 先从一级缓存
singletonObjects
中获取Bean,如果存在则直接返回。 - 如果一级缓存中不存在,且当前Bean正在创建中,则从二级缓存
earlySingletonObjects
中获取Bean,如果存在则直接返回。 - 如果二级缓存中也不存在,则从三级缓存
singletonFactories
中获取Bean工厂,如果存在则调用工厂方法创建Bean,并将Bean放入到二级缓存中,并从三级缓存中移除。
通过以上步骤,Spring就可以解决循环依赖问题。关键在于提前将实例化后的Bean放入到缓存中,并在递归时从缓存中获取Bean而不是重复创建。三级缓存的作用在于提前暴露Bean的引用,打破循环。