示例代码展示了什么是循环依赖,即ComponentA内部一个属性依赖ComponentB,而ComponentB内部一个属性依赖ComponentA。BeanFactory在创建ComponentA的依赖注入阶段,发现其依赖的ComponentB还未创建,所以转而去创建ComponentB,而在ComponnetB的依赖注入阶段,又发现其依赖的ComponentA未创建完成,面对这种循环依赖的问题,spring是怎么解决的呢?通过提前暴露仅实例化的bean来打破循环
如何理解“提前暴露仅实例化的bean”?
我们知道bean的生命周期包括:实例化、依赖注入、初始化、使用、销毁五个阶段,在ComponentA实例化之后就将ComponentA对象暴露给BeanFactory,这样ComponentB在依赖注入阶段就能注入ComponentA的依赖,进而完成ComponentB的创建,而后ComponentA在依赖注入阶段就能注入ComponentB的依赖,继续完成CompnentA的创建。
为了实现上述逻辑,BeanFactory内部存在3个Map属性
- singletonObjects:内部存放创建完毕的bean(完成了实例化、依赖注入、初始化)。
- earlySingletonObjects:内部存放仅实例化的bean(未完成依赖注入、初始化)。
- singletonFactories:内部存放"获取仅实例化bean的工厂"(提供了扩展接口,可为实例化的bean进行扩展)。
下图简要的描绘了spring如何通过这三个map解决循环依赖:
上图为了更加简洁的展示spring如何解决循环依赖,对spring实际处理逻辑做了如下简化:
- 在实例化ComponentB对象之后,也会往singletonFactories存入ComponentB对象的工厂。
- 在为ComponentB注入ComponentA的依赖时,并不是直接去singletonFacotries获取ComponentA的工厂,而是:
- 先检查singletonObjects中是否已存在完整的ComponentA对象,没有则
- 再检查earlySingletonObjects中是否存在仅实例化的ComponentA的对象,没有则
- 最后检查singletonFactories是否存在ComponentA的工厂,有则调用其getObject(),把仅实例化的ComponentA对象存入earlySingletonObjects,然后移除singletonFactories中的ComponentA的工厂
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 往singletonObjects中添加完整的ComponentA或ComponentB对象时,会清除singletonFactories、earlySingletonObjects中对应的数据。
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}