Spring源碼系列:Spring Bean實例化流程(spring是如何解決循環依賴問題的)

spring實例化bean的過程是一個比較複雜的過程,簡單的一個getBean方法 內部卻做了很多的事情。當然getBean方法也是我們再研究spring源碼道路上一個重要的方法。是不可能去繞開的,因爲很多spring的擴展接口都是基於getBean方法去展開的。

筆者這次就不去一一 的把源碼貼出來 逐行去分析了 因爲這樣我感覺效果不好。讀着讀着就不知道自己讀到那個類的哪個類的哪個方法了,所以在這裏 我以簡略的流程圖的方式來展示spring在實例化bean過程中的一些關鍵節點。讀者可以自行下去翻閱源碼看各個節點對應的具體源碼。

 

圖中 綠色節點是執行spring擴展接口的節點。也就是執行spring提供的BeanPostProcessor和BeanFactoryPostProcessor的接口或其子接口的實現。spring在容器啓動過程中和實例化bean過程中 大概前前後後有10幾個這樣的 擴展方法被執行。

看完上面的流程圖 下面我們思考一個問題:spring是如何解決循環依賴問題的?

首先什麼是循環依賴?  例如我有三個類A,B需要託管給SpringIOC容器 但是A 中注入了B  B中注入了A。形成一個環狀依賴。

爲了弄明白這個問題 我們把上圖中的2 ,8 ,9 ,11四個節點的單獨拿出來分析。

	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;
	}

假如當前處於實例化A的階段 。  代碼執行到節點11處 發現 A依賴B , 所以去遞歸實例化B   但是在實例化B之前 有一步很關鍵的操作 就是就是節點9  節點9處已經將實例A的引用註冊到singletonFactories。所以設置B的屬性的時候會執行 getSingleton方法獲取A的實例。singletonObject = singletonFactory.getObject();  這一行代碼是實例化A的時候註冊到singletonFactories的回調方法。下面我們看看節點9的源碼:

//註冊到singletonFactories
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));



protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

所以當執行 singletonFactory.getObject()就是在執行getEarlyBeanReference方法 該方法會返回一個早期的A實例的引用。

我們最後總結一下:實例一個Bean的時候 先從singletonObjects(單例緩存池) , earlySingletonObjects(早期單例緩存池),和singletonFactories(單例工廠緩存池) 中取找對應的Bean(節點2處)。如果找不到通過反射創建一個Bean 並找到當前Bean依賴的Bean註冊到當前Bean的BeanDefinition中的externallyManagedConfigMembers屬性中(節點8處 參考AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition),設置完依賴的Bean之後將當前節點註冊到singletonFactories(節點9)。然後執行設置依賴Bean從singletonFactories獲取(節點11處 設置屬性處代碼參考AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues).

這樣就解決了循環依賴的問題。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章