由上篇的分析可知,spring建立和實例化bean的過程的環節是比較多而且包裝比較深的,那麼若是每次getBean時都須要走這麼多環節的話,那麼不但會產生不少內存對象和計算邏輯,並且更重要的是沒法解決對象在一些場景中的依賴問題,尤爲是循環依賴的問題。所以spring自己也考慮到了這個問題,在建立bean的過程當中會有一些相關的緩存設計。今天咱們就一塊兒來看一下它是如何用緩存來解決的。spring
場景一、首次getBean()時
首次獲取bean時,根據上圖的流程當從一級或二級緩存中獲取,若拿到則直接返回。若沒有則直接從三級緩存中拿,當三級緩存中有緩存對象時,則經過緩存的beanFactory .getObject()直接拿到bean, 同時移除三級緩存將拿到的bean寫入二級緩存中,而後返回對象。
場景二、首次createBean()時
在doCreateBean()過程當中,若bean設置可提早暴露(默認開啓),則會建立三級緩存(beanFactory對象)
爲何會在建立三級緩存時,同時移除二級緩存?由於二級緩存中的對象是從三級緩存中獲取的,因此當三級緩存更新時會同時移除老舊的二級緩存數據,避免產生緩存數據不一致問題。緩存
在A對象中,持有對B對象的引用;同理在B對象中,也支持對A對象的引用。這種循環依賴分兩種狀況:1.在A對象中,B對象做爲A對象的成員變量;2.在A對象中,B對象做爲A對象的構造參數依賴, 這兩種方式一旦有相互成環的引用場景,就須要引發重視了。
以上截圖屬第一種狀況,spring也只有對這種狀況有考慮。這種狀況spring視爲正常引用,其它狀況spring不支持且有此狀況會直接拋出異常。ide
那麼對於以上的第一種循環依賴狀況,spring是如何解決的呢?經過構建三級緩存機制完美解決這個問題。具體的解決過程請看下面的流程圖
根據上面的解決流程圖和貼出的緩存源碼, 詳細的解釋以下:函數
OK, 看到這裏 你們是否是明白了?spring的三個等級的緩存機制設計是很值得玩味的。感興趣的能夠深刻去看下源碼。
最後要明確一個結論:只有beandefintion的Scope=Singleton類型才能進行緩存和支持以上的第一種狀況的循環依賴,其它類型的只要出現循環依賴,spring直接拋出異常。至於其它狀況爲何spring不支持你們看過源碼,應該或多或少能想獲得。設計
關於spring緩存和循環依賴的問題就先分享到這裏。有什麼關於這塊的問題能夠直接在評論區留言,更多spring源碼的乾貨請繼續關注!3d