Spring循環(huán)依賴的處理方法
循環(huán)依賴是指兩個或多個組件之間相互依賴,形成一個閉環(huán),從而導致這些組件無法正確地被初始化或加載。這種情況可能會在軟件開發(fā)中引起問題,因為循環(huán)依賴會導致初始化順序混亂,組件之間的關系變得復雜,甚至可能引發(fā)死鎖或其他不穩(wěn)定行為。
在編程中,循環(huán)依賴通常出現(xiàn)在模塊、類、或者組件之間的相互引用上,導致編譯、加載或初始化過程中的問題。在依賴注入(DI)框架中,循環(huán)依賴可能會導致對象的創(chuàng)建和初始化失敗。
@Service public class TestService1 { @Autowired private TestService2 testService2; public void test1() { } } @Service public class TestService2 { @Autowired private TestService1 testService1; public void test2() { } }
A 依賴于 B,而 B 也依賴于 A,形成了循環(huán)依賴。如果沒有適當?shù)奶幚恚跏蓟@兩個類的實例可能會導致問題。這段代碼之所以能正常運行,是因為Spring內(nèi)部機制,解決了循環(huán)依賴的問題。
Spring內(nèi)部有三級緩存:
- singletonObjects 一級緩存,用于保存實例化、注入、初始化完成的bean實例
- earlySingletonObjects 二級緩存,用于保存實例化完成的bean實例
- singletonFactories 三級緩存,用于保存bean創(chuàng)建工廠,以便于后面擴展有機會創(chuàng)建代理對象。
Spring解決循環(huán)依賴步驟:
- Bean 的注冊:首先,Spring會解析并注冊所有的Bean定義,但不會立即創(chuàng)建Bean的實例。
- 提前創(chuàng)建 Bean 實例:對于每個要創(chuàng)建的單例(
@Service
默認是單例作用域),Spring會提前創(chuàng)建一個半初始化的實例,并將其放入singletonFactories
緩存中。這是為了解決循環(huán)依賴問題。 - 開始創(chuàng)建 TestService1:當開始創(chuàng)建
TestService1
時,發(fā)現(xiàn)它依賴于TestService2
。因為TestService2
的半初始化實例已經(jīng)在singletonFactories
緩存中,所以會使用該實例創(chuàng)建TestService1
,并在singletonFactories
緩存中移除TestService2
的工廠。 - 開始創(chuàng)建 TestService2:當創(chuàng)建
TestService2
時,發(fā)現(xiàn)它依賴于TestService1
,但由于TestService1
的半初始化實例已經(jīng)存在,所以會使用該實例創(chuàng)建TestService2
,并在singletonFactories
緩存中移除TestService1
的工廠。 - 完全初始化:一旦創(chuàng)建過程完成,Spring會執(zhí)行
TestService1
和TestService2
的初始化操作,包括注入和其他初始化方法。這將使它們變成完全初始化的Bean
圖解:
循環(huán)依賴可能出現(xiàn)的場景
- 模塊之間的相互引用:在模塊化的軟件設計中,不同模塊之間可能會相互引用,特別是當模塊之間存在交叉的功能需求或依賴時。如果模塊之間的依賴關系沒有正確管理,就可能產(chǎn)生循環(huán)依賴。
- 類的相互引用:在面向?qū)ο缶幊讨?,不同類之間可能會有相互引用,尤其是在它們之間存在雙向的依賴關系時。如果類的構造函數(shù)或方法參數(shù)中出現(xiàn)了相互引用,就可能導致循環(huán)依賴問題。
- 依賴注入框架配置不當:依賴注入框架(如Spring)用于管理組件之間的依賴關系。如果配置文件中出現(xiàn)了循環(huán)依賴,框架可能無法正確初始化對象,導致異常。
- 事件和消息驅(qū)動的系統(tǒng):在事件和消息驅(qū)動的系統(tǒng)中,不同組件可能通過事件或消息進行通信。如果事件的發(fā)起者和接收者之間出現(xiàn)相互依賴,就可能導致循環(huán)依賴。
- 單例模式的使用:當使用單例模式時,如果多個單例對象之間相互依賴,可能會形成循環(huán)依賴。單例對象在整個應用程序中只有一個實例,因此其依賴關系需要特別注意。
- 構建和初始化順序問題:在某些情況下,對象的構建和初始化順序可能導致循環(huán)依賴。如果某個對象在構建階段需要引用另一個對象,而后者又需要在構建階段引用前者,就可能形成循環(huán)依賴。
如何解決循環(huán)依賴
- 重構設計:重新審視組件之間的關系,嘗試將循環(huán)依賴問題轉(zhuǎn)化為單向的依賴關系。這可能需要重新劃分模塊或類的職責,以減少相互依賴。
- 引入接口或抽象類:通過引入接口或抽象類,可以將具體的依賴關系替換為更高層次的抽象依賴,從而解耦循環(huán)依賴。
- 延遲初始化:將對象的初始化推遲到實際使用它們的時候,以避免在初始化階段出現(xiàn)循環(huán)依賴。這可以通過懶加載等方式來實現(xiàn)。
- 使用中介者模式:引入中介者或事件系統(tǒng),將類之間的通信轉(zhuǎn)移到中介者中,從而降低直接的循環(huán)依賴。這可以將相互依賴的關系集中在一個地方進行處理。
- 使用依賴注入容器:依賴注入框架(如Spring)可以處理循環(huán)依賴問題。這些框架使用一些特殊的策略,以確保對象的正確初始化順序,從而解決循環(huán)依賴。
- 通過Setter注入或后處理器解決:在某些情況下,通過使用Setter方法注入依賴或使用依賴后處理器可以解決循環(huán)依賴問題。這樣,對象的構建和初始化可以分為多個步驟。
- 更改對象創(chuàng)建時機:有時,將對象的創(chuàng)建從構造函數(shù)移至其他方法中,可以避免在構造函數(shù)階段引發(fā)循環(huán)依賴。
- 設計模式:一些設計模式,如工廠方法模式、抽象工廠模式,可以用來分離對象的構建和初始化,從而避免循環(huán)依賴。
到此這篇關于Spring循環(huán)依賴的處理的文章就介紹到這了,更多相關Spring循環(huán)依賴內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot+WebMagic+MyBatis爬蟲框架的使用
本文是對spring boot+WebMagic+MyBatis做了整合,使用WebMagic爬取數(shù)據(jù),然后通過MyBatis持久化爬取的數(shù)據(jù)到mysql數(shù)據(jù)庫。具有一定的參考價值,感興趣的可以了解一下2021-08-08springcloud結(jié)合bytetcc實現(xiàn)數(shù)據(jù)強一致性原理解析
這篇文章主要介紹了springcloud結(jié)合bytetcc實現(xiàn)數(shù)據(jù)強一致性原理解析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03