別再讓循環(huán)依賴成為你的噩夢,Spring助你一臂之力

大家好,我是小米,今天我們來聊聊 Spring 框架中的一個重要話題:循環(huán)依賴。在開發(fā)中,我們可能會遇到這樣的問題:兩個或多個 bean 之間相互依賴,導(dǎo)致創(chuàng)建對象時出現(xiàn)死循環(huán)。那么,Spring 是如何解決這個問題的呢?
什么是循環(huán)依賴
在 Spring 中,bean 之間的依賴關(guān)系可以通過構(gòu)造函數(shù)注入、Setter 注入、接口注入等方式實現(xiàn)。當兩個或多個 bean 相互依賴時,就會形成循環(huán)依賴。比如,bean A 依賴于 bean B,而 bean B又依賴于 bean A,這就是循環(huán)依賴。
Spring 如何解決循環(huán)依賴
Spring使用“三級緩存”來解決循環(huán)依賴的問題。三級緩存指的是singletonObjects、earlySingletonObjects和singletonFactories三個Map。
在Spring創(chuàng)建對象時,會先檢查 singletonObjects 中是否已經(jīng)存在該對象的實例,如果存在,則直接返回該實例;如果不存在,則檢查 earlySingletonObjects 中是否已經(jīng)存在該對象的“提前曝光”的代理對象,如果存在,則返回該代理對象,否則就調(diào)用singletonFactories 中存儲的工廠方法來創(chuàng)建該對象的實例,并將其放入 earlySingletonObjects 中,同時存儲一個 Factory 對象到singletonFactories 中。
當對象創(chuàng)建完成之后,就會從 earlySingletonObjects中 移除該對象的代理對象,將完整的對象實例放入 singletonObjects 中,并清空 singletonFactories中的Factory 對象。這樣,下次獲取該對象的實例時,就可以直接從 singletonObjects 中獲取了。
三級緩存是如何解決循環(huán)依賴
當出現(xiàn)循環(huán)依賴時,Spring 會將正在創(chuàng)建的對象提前曝光,也就是將一個代理對象放到 earlySingletonObjects 中,然后在創(chuàng)建對象時,將代理對象注入到另一個需要依賴該對象的 bean 中。這樣,當需要使用該對象時,就可以從 earlySingletonObjects 中獲取到代理對象,避免了死循環(huán)的出現(xiàn)。
緩存為什么是三級
三級緩存可以保證對象的單例性,同時也可以解決循環(huán)依賴的問題。而單例對象的創(chuàng)建和獲取是很頻繁的操作,所以使用三級緩存可以提高效率。
緩存的放置時間和刪除時間
三級緩存:當 Spring 創(chuàng)建一個bean的實例時,會將其放入singletonFactories中,這個操作是在createBeanInstance之后完成的。同時,也會將該 bean 的工廠方法放入singletonFactories中。這樣,當需要獲取該 bean 的實例時,就可以從 singletonFactories 中獲取到其對應(yīng)的工廠方法。
二級緩存:當 Spring 從 singletonFactories 中獲取到一個bean 的工廠方法后,會通過該工廠方法創(chuàng)建該 bean 的實例,并將其放入 earlySingletonObjects 中。同時,也會將其代理對象放入 earlySingletonObjects 中。
在后續(xù)創(chuàng)建依賴該 bean 的其他 bean 時,如果需要獲取該bean 的實例,就會從 earlySingletonObjects 中獲取到其代理對象。在第一次從 earlySingletonObjects 中獲取到該代理對象時,Spring 會判斷該對象是代理對象還是普通對象,如果是代理對象,則會將其替換為其對應(yīng)的普通對象,并從 earlySingletonObjects 中刪除該代理對象。
一級緩存:當Spring創(chuàng)建完一個bean的完整實例后,會將其放入 singletonObjects 中,并從 earlySingletonObjects中刪除其對應(yīng)的代理對象和工廠方法。同時,也會將其對應(yīng)的bean的依賴項從 dependencyCheck 中移除。這樣,下次獲取該bean的實例時,就可以直接從 singletonObjects 中獲取了。
提前曝光來解決循環(huán)依賴(不推薦)
除了三級緩存之外,提前曝光是 Spring 解決循環(huán)依賴問題的重要手段之一。當 Spring 創(chuàng)建一個 bean 的實例時,如果檢測到其依賴了另一個正在創(chuàng)建的 bean,則會將其提前曝光,即將一個代理對象放入 earlySingletonObjects 中,以便在后續(xù)創(chuàng)建依賴該 bean 的其他 bean 時,可以直接使用其代理對象,避免了死循環(huán)的出現(xiàn)。不過,提前曝光的方法需要手動配置,比較麻煩,所以一般情況下,我們都會使用 Spring 提供的三級緩存來解決循環(huán)依賴的問題。
END
總的來說,Spring 是一個非常優(yōu)秀的 Java 框架,它不僅提供了依賴注入和 AOP 等常用功能,還能夠很好地解決循環(huán)依賴的問題。而這些都離不開 Spring 框架底層的設(shè)計和實現(xiàn)。希望今天的分享能夠幫助大家更好地理解 Spring 框架的原理和實現(xiàn),也希望大家能夠繼續(xù)深入學(xué)習(xí)和研究 Java 技術(shù),不斷提升自己的能力。謝謝大家的閱讀!
如有疑問或者更多的技術(shù)分享,歡迎關(guān)注我的微信公眾號“知其然亦知其所以然”!
