首頁>技術>

先上個整體流程圖,有個初始印象,後面比較詳細的解析。

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@aaa
protected 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迴圈依賴

現在看下來是不是感覺很好理解了,不過還是建議跟著原始碼走一下,加深印象!~~~

26
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 2020年馬上就要過去了,這些程式碼共享網站你不會還沒用過吧