spring对循环依赖的解决

22 阅读2分钟

示例代码展示了什么是循环依赖,即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属性

  1. singletonObjects:内部存放创建完毕的bean(完成了实例化、依赖注入、初始化)。
  2. earlySingletonObjects:内部存放仅实例化的bean(未完成依赖注入、初始化)。
  3. singletonFactories:内部存放"获取仅实例化bean的工厂"(提供了扩展接口,可为实例化的bean进行扩展)。

下图简要的描绘了spring如何通过这三个map解决循环依赖:

画板

上图为了更加简洁的展示spring如何解决循环依赖,对spring实际处理逻辑做了如下简化:

  1. 在实例化ComponentB对象之后,也会往singletonFactories存入ComponentB对象的工厂。
  2. 在为ComponentB注入ComponentA的依赖时,并不是直接去singletonFacotries获取ComponentA的工厂,而是:
    1. 先检查singletonObjects中是否已存在完整的ComponentA对象,没有则
    2. 再检查earlySingletonObjects中是否存在仅实例化的ComponentA的对象,没有则
    3. 最后检查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;
	}

  1. 往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);
		}
	}