天天看點

Spring三級緩存解決循環依賴問題

作者:馬士兵教育

前提知識

1、解決循環依賴的核心依據:執行個體化和初始化步驟是分開執行的

2、實作方式:三級緩存

3、lambda表達式的延遲執行特性

spring源碼執行邏輯

Spring三級緩存解決循環依賴問題

核心方法refresh(), populateBean()填充bean對象,設定屬性值;

getEarlyBeanReference() 在未完成屬性指派之前,提前暴露代理對象,在指派的時候才确定真實對象。

Spring三級緩存解決循環依賴問題

1、三個map結構分别存儲什麼類型的對象?

Spring三級緩存解決循環依賴問題

-級緩存:成品對象

級緩存:半成品對象

三級緩存:lambda表達式

2、三個map結構在進行對象查找的時候,查找的順序是什麼樣的?

1, 2, 3

3、為什麼一級緩存有對象之後就要把二級和三級給移除掉?

Spring三級緩存解決循環依賴問題

因為對象的查找順序是1,2,3,如果在一級中找到了,那麼二級永遠也不會進行查找,以此類推

4、如果隻有一個map結構,能否解決循環依賴問題?

原則上是可以的,但是操作起來比較麻煩,當隻有一個map結構的時候就意味着成品對象和半成品對象要放到一起,而半成品對象是不能暴露給外部使用的,要不會報空指針異常,是以需要添加辨別位,而容器中對象的名字都是固定的,是以辨別位隻能在value中,也就意味着每次在判斷的時候都要擷取到value然後判斷完标志位之後才能進行下一步操作,比較麻煩,直接用兩個map可以輕松解決這個問題

5、如果隻有兩個map結構,能否解決循環依賴問題?

原則上是可以的,但是有前提條件:整個代碼的執行邏輯中不能包含代理對象的建立,否則會報錯

6、為什麼必須要使用三個map結構來解決循環依賴問題?三級緩存是如何解決循環依賴問題的?

(1)在建立代理對象的時候是否需要建立原始對象?

需要

(2)容器中能否同時存在兩個同名的不同對象?

不能

(3)如果建立出了代理對象,那麼原始對象應該怎麼處理?

當建立出代理對象之後,需要将代理對象覆寫原始對象

(4)那麼為什麼要引入三級緩存呢?為什麼要傳入一個lambda表達式呢?

正常的bean的生命周期是先通過createBeanlnstance建立出原始對象,然後在populateBean的方法中完成對象屬性的指派工作,然後在BeanPostProcessor的後置處理方法中完成代理對象的建立工作,也就是說按照正常的執行邏輯,是完成屬性的指派之後才會建立出代理對象,那麼意味着最後建立出的是代理對象,但是指派的時候賦的是原始對象,是以會出現一個錯誤:that said other beans do not use the final version of the bean. 當引入lambda表達式之後相當于将生成代理對象的過程給提前了,也就是說在完成對象的屬性指派的時候必須要唯一性的确定好我需要的到底是代理對象還是原始對象,參考 (getEarlyBeanReference方法)也就是說我們在指派的前一刻必須要确定好最終的結果,但是又因為我們沒有辦法确定什麼時刻會給什麼對象的屬性指派,是以采用lambda表達式的方法延遲執行,隻有在對象指派的最後一刻才确定出到底是什麼對象。

Spring三級緩存解決循環依賴問題