天天看點

Spring源碼是如何解決Bean的循環依賴

首先需要明白一點,隻有scop為(singleton)單例類型的Bean,spring才支援循環依賴。scope為(prototype)原型類型的Bean是不支援的,它每次調用都會建立一個新的執行個體,spring 在執行個體化bean的時候會先執行個體化bean的各種屬性依賴,如果TestA TestB是原型類型且互相依賴則會出現new TestA 的時候,先new TestB,然後new TestB的時候又去new TestA會出現無限套娃的情況。
兩個單例testA testB 互相依賴的執行個體化過程:
  1. Spring容器建立單例“testA”bean,首先根據無參構造器建立bean,并暴露一個“ObjectFactory”用于傳回一個提前暴露正在建立中的bean,并将“testA”辨別符放到“目前建立bean池”,然後進行setter注入“testB”。
  2. Spring容器建立單例“testB”bean,首先根據無參構造器建立bean,并暴露一個“ObjectFactory”用于傳回一個提前暴露正在建立中的bean,并将“testB”辨別符放到“目前建立bean池”,然後進行setter注入“testA”,此時由于通過 暴露"ObjectFactory" 已提前暴露了一個正在建立中的"testA" bean,是以直接注入,完成testB的建立,注入testA中,再完成testA的建立。

源碼中的實作方式:

首先了解一下建立Bean過程中最重要的三個map
以下三個Map均來自于 DefaultSingletonBeanRegistry

Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

  • singletonObjects:用于儲存BeanName和建立bean執行個體之間的關系,bean name 一> bean instance。
  • singletonFactories:用于儲存BeanName和建立bean的工廠之間的關系,bean name 一>ObjectFactory。
  • earlySingletonObjects:也是儲存BeanName和建立bean執行個體之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這裡面後,那麼當bean還在建立過程中,就可以通過getBean方法擷取到了,其目的是用來檢測循環引用。
總結: 後面兩個Map實際上就是為了輔助第一個Map緩存Bean的執行個體,完成後資料就在後面兩個Map中清掉了。

測試代碼:

// 1. 引入依賴,springboot項目隻需要這一個依賴即可測試
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
// 2. 兩個測試類
@Component
public class TestA {
    @Autowired
    private TestB testB;
}
@Component
public class TestB {
    @Autowired
    private TestA testA;
}
           
注意:下面所有的方法都隻是源碼的部分截取,把我認為重要的邏輯放在這裡的,大家閱讀時,可提前在IDE中打開文中提到的幾個類,在相應方法處,打上斷點可以直接調試,bean的執行個體化過程就一目了然了。
1. AbstractBeanFactory 類中 getBean方法
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
		throws BeansException {
	return doGetBean(name, requiredType, args, false);
}
           
2. AbstractBeanFactory 類中 doGetBean方法
// 
// 2.1 從緩存中擷取執行個體Bean,第一次肯定沒有,為null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
	beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
	// Create bean instance.
	if (mbd.isSingleton()) {
		// 2.2 擷取緩存中的執行個體
		sharedInstance = getSingleton(beanName, () -> {
			try {
				// 2.3 調用建立Bean執行個體的方法
				return createBean(beanName, mbd, args);
			}	
		});
		beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
}
           
3. DefaultSingletonBeanRegistry 類中 getSingleton方法,2.1調用的就是這裡的3.1
// 3.1
@Override
@Nullable
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}
// 3.2
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		singletonObject = this.earlySingletonObjects.get(beanName);
		if (singletonObject == null && allowEarlyReference) {
			synchronized (this.singletonObjects) {
				// Consistent creation of early reference within full singleton lock
				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;
}
           
3.1 和 3.2後面會反複擷取的,第一次因為isSingletonCurrentlyInCreation(beanName)傳回false,是以傳回null
4. DefaultSingletonBeanRegistry 類中 getSingleton方法,擷取ObjectFactory,2.2就是調用的這裡
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			try {
				// 4.0.1
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			finally {
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
				// 4.0.2
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

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);
	}
}
           
這面重點分析beforeSingletonCreation 、afterSingletonCreation 和 addSingleton這三個方法
4.1 DefaultSingletonBeanRegistry 中 beforeSingletonCreation方法 和 afterSingletonCreation方法
protected void beforeSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
protected void afterSingletonCreation(String beanName) {
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
	}
}
           
重點:這兩個方法的目的就是為 singletonsCurrentlyInCreation 這個set集合添加和删除目前建立的Bean,為後續處理做鋪墊,addSingleton方法主要是對Bean緩存map的維護。
4.2 現在回到第4步的4.0.1的方法中,

singletonObject = singletonFactory.getObject();

這行代碼就是正真擷取執行個體對象的地方,singletonFactory 是怎麼拿到的呢,這就要回到第2步的2.3步驟中,通過createBean方法傳回了ObjectFactory類型的singletonFactory,下面看createBean是如何建立Bean的:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {		
	try {
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		return beanInstance;
	}	
}
// 看過一些spring源碼的都應該明白spring真正做事情的都是以doXXX開頭的,這裡也不例外
// 相信大家都已經明白真正建立Bean是由doCreateBean方法實作的,下面我們繼續分析這個方法
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
	BeanWrapper instanceWrapper = null;
	if (instanceWrapper == null) {
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	Object bean = instanceWrapper.getWrappedInstance();
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
	 && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	Object exposedObject = bean;
	try {
		// 4.3 填充Bean的屬性,依賴bean就是這裡初始化的
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	if (earlySingletonExposure) {
		// 4.4 再次擷取緩存中的執行個體,注意這裡可以從兩個緩存處擷取,第一個是earlySingletonObjects map,第二個是singletonFactories map擷取
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
		}
	}
	return exposedObject;
}
// isSingletonCurrentlyInCreation方法
public boolean isSingletonCurrentlyInCreation(String beanName) {
	return this.singletonsCurrentlyInCreation.contains(beanName);
}
// addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
	if (!this.singletonObjects.containsKey(beanName)) {
		this.singletonFactories.put(beanName, singletonFactory);
		this.earlySingletonObjects.remove(beanName);
		this.registeredSingletons.add(beanName);
	}
}
           

重要流程梳理:

1.doCreateBean中主要分為兩部分,第一部分通過instanceWrapper得到BeanFactory的執行個體,内部由反射實作,這裡我們不多做分析,變量earlySingletonExposure,它由三部分得到,前面兩個都很容易了解,第三部分則出現了我們在4.1中做鋪墊的集合 singletonsCurrentlyInCreation。由于在4.1中已經設定了,是以earlySingletonExposure肯定為true,是以執行addSingletonFacatory為singletonFactories map指派,完成了beanName -> ObjectFactory的映射

2.populateBean方法中則會完成對Bean依賴屬性的注入,是以代碼走到4.3的時候,testA的建立就停止了,會回到第一步去擷取testB,然後又是對testB的建立,最後會再次走到4.3,完成testA 和 testB 的ObjectFactory的映射,即将它們放入 singletonFactories map緩存中。

3. 建立testB 再次走到4.3的時候,又會去初始化testB的依賴 testA,此時會再次去第一步擷取,再次走到2.1的時候,因為testA的ObjectFactory是有值的,是以通過它能夠擷取到testA 的singletonObject,此時就把testA 的執行個體放入了 earlySingletonObjects中,隻不過此時的testA執行個體是不完整的,還沒有完成屬性testB依賴的初始化。最後傳回testA的singletonObject引用,完成testB對其依賴testA的初始化,然後再去 4.4 擷取testB的緩存,這裡依舊是沒有的,然後傳回到4.0.2處,将testB加入singletonObjects map緩存,并移除testB在singletonFactories中的緩存,這裡testB 在 earlySingletonObjects中實際上是沒有值的,當然有的話也會移除,因為singletonObjects 中已經拿到值了,是以另外兩個輔助map就不用保留資料了。

4. 上面已經完成testB的初始化并放入singletonObjects 緩存了,繼續走,就又回到了4.3,繼續完成對testA的建立,走到4.4的時候,繼續去緩存中擷取testA,因為之前已經把testA放入earlySingletonObjects map中了,是以4.4是直接能夠擷取到testA的執行個體的。

5. 繼續走,就又來到了4.0.2,不過這次是針對testA的,addSingleton方法中會把testA的執行個體給放入singletonObjects map緩存中,同時移除singletonFactories 和 earlySingletonObjects map緩存的testA,完成testA和testB的執行個體化。