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).
這樣就解決了循環依賴的問題。