先上個整體流程圖,有個初始印象,後面比較詳細的解析。
Spring迴圈依賴解析
從BeanFactory中獲取單例物件最終呼叫的方法是doGetBean方法,內部首先呼叫getSingleton方法來判斷當前要獲取的bean是否已經被建立或者是正在建立。
BeanFactory中有三個map型別的屬性:
singletonObjects:存放例項化並初始化完成的單例物件引用earlySingletonObjects:存放單例物件提前曝光的物件引用singletonFactories:存放提供建立早期單例引用的物件工廠,該工廠例項建立的物件會存放到earlySingletonObjects中三者關係:
singletonObjects中存在beanName=A時,其他兩個不存在singletonObjects中不存在beanName=A時,其他兩個要麼也不存在,要麼只有一個存在getSingleton方法
addSingleton方法
getSingleton方法獲取物件時訪問這三個map物件的順序【此時allowEarlyReference=true】:
訪問singletonObjects,如果返回空,下一步訪問earlySingletonObjects,如果返回空,下一步訪問singletonFactories,如果返回空,則開始建立單例物件;如果返回不為空,返回的就是ObjectFactory,然後呼叫ObjectFactory的getObject方法,然後從singletonFactories中移除該ObjectFactory然後將getObject呼叫結果存入earlySingletonObject示例解析:
如下有兩個服務實現類A和B
@Service("A")public class AServiceImpl implements IAService { @Autowired private IBService bService;}@Service("B")public class BServiceImpl implements IBService { @Autowired private IAService aService;}
再加深點印象:
Spring迴圈依賴解析
步驟解析【假設在bean的例項化中先例項化A】:
從singletonObjects這個map物件中獲取beanName為A的物件,為空,繼續從earlySingletonObjects這個map物件中獲取beanName為A的早期物件,為空,繼續從singletonFactories這個map物件中獲取beanName為A的ObjectFactory物件,為空,則進行A的單例物件的例項化,步驟如下:透過doCreateBean方法建立A的例項,記為例項A@aaa,簡單理解就是透過構造方法反射建立了A的例項,此時例項A@aaa的成員變數bService為null往singletonFactories中put一個對應beanName為A的ObjectFactory的物件,程式碼如下:if (earlySingletonExposure) { // 預設是為true的,允許及早曝光 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}
填充例項A@aaa中的成員變數bService,但此時B型別的例項並未建立,因此開始建立B的例項,步驟如下:1、從singletonObjects、earlySingletonObjects、singletonFactories這個map物件中獲取beanName為B的相關物件,都為空,繼續
2、透過doCreateBean方法建立B的例項,記為例項B@bbb,簡單理解就是透過構造方法反射建立了B的例項,此時例項B@bbb的成員變數aService為null
3、往singletonFactories中put一個對應beanName為B的ObjectFactory的物件
4、填充例項B@bbb的成員變數aService,此時會從BeanFactory中獲取A型別的例項物件:
從singletonObjects中獲取A的單例物件-->為空,繼續
從earlySingletonObjects中獲取A的早期物件-->為空,繼續
從singletonFactories獲取A的ObjectFactory-->不為空,因為建立A的例項A@aaa的之後,往這個map中放入了A對應的ObjectFactory,(沒印象的話往前面翻幾行),此時透過獲取到的ObjectFactory.getObject方法進一步呼叫getEarlyBeanReference這個方法,程式碼如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { // 呼叫SmartInstantiationAwareBeanPostProcessor型別的後置處理器 // 的getEarlyBeanReference方法來建立早期可以暴露的例項物件 exposedObject = bp.getEarlyBeanReference(exposedObject, beanName); } } return exposedObject;}
5、這段程式碼的作用是:如果A類中的方法如果需要被系統定義的一些增強器(如使用AspectJ定義的一些通知)增強的話,則需要為A的例項建立一個代理物件(使用CGLIB的話則是建立一個A的子類A$$CGLIB$$A.class,然後例項化這個子類的物件,記為例項A$$CGLIB$$A@aaa,而例項A$$CGLIB$$A@aaa的屬性中將會持有當前建立的A的例項A@aaa的一個引用,然後返回例項A$$CGLIB$$A@aaa,也就是代理物件),如果不需要代理的話,則直接返回例項A@aaa。
6、獲取到A的例項物件後(此時獲取的是A例項A@aaa的代理物件$$CGLIB$$A@aaa或就是本身A@aaa),將A的例項物件填充到B例項B@bbb的成員屬性aService中,後面再對例項B@bbb進行初始化等其他操作.....略過,最後將B例項B@bbb放入到BeanFactory的singletonObjects中,程式碼見下下下方。
7、此時B例項B@bbb建立完畢並返回,然後返回到對例項A@aaa的填充成員屬性bService的步驟:
繼續A例項的處理:
獲取到新建立的B例項B@bbb之後,將B@bbb填充到A例項A@aaa的bService成員屬性中執行A例項A@aaa的初始化方法:// 執行afterPropertiesSet方法(如果有的話),initMethod(如果有的話)initializeBean(beanName, exposedObject, mbd);
...省略一些判斷細節,後面還會呼叫一次getSingleton方法,如果A例項A@aaa被代理了,放入BeanFactory的singletonObjects這個map物件中的例項就是$$CGLIB$$A@aaa,沒有被代理放入的就是A@aaaprotected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 放入singletonObjects this.singletonObjects.put(beanName, singletonObject); // 從singletonFactories中移除A this.singletonFactories.remove(beanName); // 從earlySingletonObjects中移除A this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); }}
再次回顧下整體流程:
Spring迴圈依賴
現在看下來是不是感覺很好理解了,不過還是建議跟著原始碼走一下,加深印象!~~~