欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中循環(huán)依賴的常見陷阱與解決方案

 更新時間:2025年05月21日 10:42:10   作者:悟能不能悟  
循環(huán)依賴指兩個或多個Bean相互依賴對方,形成一個閉環(huán),本文將深入探討循環(huán)依賴的根源,分析Spring的解決策略,并提供多種實戰(zhàn)解決方案,希望對大家有所幫助

引言

在Spring Boot開發(fā)中,你是否遇到過這樣的錯誤信息?

The dependencies of some of the beans in the application context form a cycle

這表示你的應用出現(xiàn)了循環(huán)依賴。盡管Spring框架通過巧妙的機制解決了部分循環(huán)依賴問題,但在實際開發(fā)中(尤其是使用構(gòu)造器注入時),開發(fā)者仍需警惕此類問題。本文將深入探討循環(huán)依賴的根源,分析Spring的解決策略,并提供多種實戰(zhàn)解決方案。

一、什么是循環(huán)依賴

循環(huán)依賴指兩個或多個Bean相互依賴對方,形成一個閉環(huán)。例如:

  • ?Bean A? 的創(chuàng)建需要注入 ?Bean B?
  • ?Bean B? 的創(chuàng)建又需要注入 ?Bean A?

此時,Spring容器在初始化Bean時會陷入“死循環(huán)”。以下是一個典型示例:

@Service
public class ServiceA {
    private final ServiceB serviceB;
    
    public ServiceA(ServiceB serviceB) { // 構(gòu)造器注入ServiceB
        this.serviceB = serviceB;
    }
}
 
@Service
public class ServiceB {
    private final ServiceA serviceA;
    
    public ServiceB(ServiceA serviceA) { // 構(gòu)造器注入ServiceA
        this.serviceA = serviceA;
    }
}

啟動應用時,Spring會拋出異常:

BeanCurrentlyInCreationException: Error creating bean with name 'serviceA': Requested bean is currently in creation

二、Spring如何解決循環(huán)依賴

Spring通過三級緩存機制解決單例Bean的循環(huán)依賴問題:

  • ?一級緩存?(singletonObjects):存放完全初始化好的Bean。
  • ?二級緩存?(earlySingletonObjects):存放提前曝光的半成品Bean(僅實例化,未填充屬性)。
  • ?三級緩存?(singletonFactories):存放Bean的工廠對象,用于生成半成品Bean。

?解決流程?(以A和B相互依賴為例):

  • 創(chuàng)建A時,先實例化A(未填充屬性),并將A的工廠放入三級緩存。
  • 填充A的屬性時發(fā)現(xiàn)需要B,開始創(chuàng)建B。
  • 創(chuàng)建B時,實例化B后,發(fā)現(xiàn)需要A,此時從三級緩存中通過工廠獲取A的半成品對象。
  • B完成初始化,放入一級緩存。
  • A繼續(xù)填充B的實例,完成初始化,放入一級緩存。

?關(guān)鍵限制?:該機制僅支持單例Bean且通過屬性注入的場景。?構(gòu)造器注入會直接失?。?/p>

三、為何構(gòu)造器注入會導致循環(huán)依賴失敗

構(gòu)造器注入要求Bean在實例化階段立即獲得依賴對象,而三級緩存機制需要在屬性注入階段解決依賴。因此,當兩個Bean都使用構(gòu)造器注入時,Spring無法提前曝光半成品Bean,導致循環(huán)依賴無法解決。

四、解決方案:打破循環(huán)依賴的四種方法

1. ?改用Setter/Field注入(謹慎使用)??

將構(gòu)造器注入改為Setter或字段注入,允許Spring延遲注入依賴:

@Service
public class ServiceA {
    private ServiceB serviceB;
    
    @Autowired // Setter注入
    public void setServiceB(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

?優(yōu)點?:快速解決問題。

?缺點?:破壞了不可變性(字段非final),且可能掩蓋設計問題。

2. ?使用@Lazy延遲加載?

在依賴對象上添加@Lazy,告知Spring延遲初始化Bean:

@Service
public class ServiceA {
    private final ServiceB serviceB;
    
    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB; // 實際注入的是代理對象
    }
}

?原理?:Spring生成代理對象,只有在首次調(diào)用時才會真正初始化目標Bean。

?適用場景?:解決構(gòu)造函數(shù)注入的循環(huán)依賴。

3. ?重新設計代碼結(jié)構(gòu)?

通過分層或提取公共邏輯,消除循環(huán)依賴:

?方案一?:引入中間層(如ServiceC),將A和B的共同依賴轉(zhuǎn)移到C。

?方案二?:使用事件驅(qū)動(ApplicationEvent),解耦直接依賴。

// 事件驅(qū)動示例
@Service
public class ServiceA {
    @Autowired
    private ApplicationEventPublisher eventPublisher;
 
    public void doSomething() {
        eventPublisher.publishEvent(new EventA());
    }
}
 
@Service
public class ServiceB {
    @EventListener
    public void handleEventA(EventA event) {
        // 處理事件
    }
}

4. ?使用ObjectProvider(推薦)??

在構(gòu)造器中注入ObjectProvider,按需獲取依賴:

@Service
public class ServiceA {
    private final ServiceB serviceB;
    
    public ServiceA(ObjectProvider<ServiceB> serviceBProvider) {
        this.serviceB = serviceBProvider.getIfUnique();
    }
}

?優(yōu)點?:保持構(gòu)造器注入的不可變性,顯式控制依賴獲取時機。

?注意?:需確保依賴Bean存在且唯一。

五、最佳實踐與預防措施

1.?優(yōu)先使用構(gòu)造器注入?:保持Bean的不可變性和明確依賴,但需警惕循環(huán)依賴。

2.?定期檢測循環(huán)依賴?:

使用IDE插件(如IntelliJ的Circular Dependencies分析)。

通過Maven/Gradle插件(如spring-boot-dependencies-analysis)。

3.?代碼分層規(guī)范?:

嚴格遵循分層架構(gòu)(Controller → Service → Repository)。

避免同一層內(nèi)的Bean相互依賴。

4.?單元測試驗證?:編寫集成測試,驗證Bean的初始化過程。

@SpringBootTest
public class CircularDependencyTest {
    @Autowired
    private ApplicationContext context;
 
    @Test
    void contextLoads() {
        // 若啟動無異常,則通過測試
        assertNotNull(context.getBean(ServiceA.class));
    }
}

六、總結(jié)

循環(huán)依賴是Spring開發(fā)中的常見陷阱,其本質(zhì)是代碼設計問題。盡管Spring提供了部分解決方案,但重構(gòu)代碼消除循環(huán)依賴才是根本之道。通過合理使用注入方式、代碼分層和工具檢測,開發(fā)者可以有效避免此類問題,構(gòu)建高可維護性的應用。

?記住?:

  • 慎用@Lazy和Setter注入,它們可能掩蓋設計缺陷。
  • 構(gòu)造器注入 + 合理分層 = 更健壯的系統(tǒng)!

到此這篇關(guān)于SpringBoot中循環(huán)依賴的常見陷阱與解決方案的文章就介紹到這了,更多相關(guān)SpringBoot循環(huán)依賴內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于springboot+vue實現(xiàn)垃圾分類管理系統(tǒng)

    基于springboot+vue實現(xiàn)垃圾分類管理系統(tǒng)

    這篇文章主要為大家詳細介紹了基于springboot+vue實現(xiàn)垃圾分類管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • win10 java(jdk安裝)環(huán)境變量配置和相關(guān)問題

    win10 java(jdk安裝)環(huán)境變量配置和相關(guān)問題

    這篇文章主要介紹了win10java(jdk安裝)環(huán)境變量配置和相關(guān)問題解決,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • SpringBatch跳過異常和限制方式

    SpringBatch跳過異常和限制方式

    這篇文章主要介紹了SpringBatch跳過異常和限制方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot基于Redis實現(xiàn)短信登錄的操作

    SpringBoot基于Redis實現(xiàn)短信登錄的操作

    驗證碼登錄是非常常見的一種登錄方式,能夠簡化用戶登錄的過程,本文主要介紹了SpringBoot基于Redis實現(xiàn)短信登錄的操作,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Java中&和&&的區(qū)別簡單介紹

    Java中&和&&的區(qū)別簡單介紹

    這篇文章主要介紹了Java中&和&&的區(qū)別,&&邏輯與||邏輯或  它們都是邏輯運算符,& 按位與|按位或它們都是位運算符,更多詳細內(nèi)容請需要的小伙伴了解下面文章內(nèi)容
    2022-01-01
  • Java中不用第三個變量來互換兩個變量的值

    Java中不用第三個變量來互換兩個變量的值

    在程序運行期間,隨時可能產(chǎn)生一些臨時數(shù)據(jù),應用程序會將這些數(shù)據(jù)保存在一些內(nèi)存單元中,每個內(nèi)存單元都用一個標識符來標識。這些內(nèi)存單元被稱為變量,定義的標識符就是變量名,內(nèi)存單元中存儲的數(shù)據(jù)就是變量的值
    2021-10-10
  • Spring?Boot?如何正確讀取配置文件屬性

    Spring?Boot?如何正確讀取配置文件屬性

    這篇文章主要介紹了Spring?Boot?如何正確讀取配置文件屬性,項目中經(jīng)常會經(jīng)常讀取配置文件中的屬性的值,Spring?Boot提供了很多注解讀取配置文件屬性,那么如何正確使用呢,下文一起來參考下面文章內(nèi)容吧
    2022-04-04
  • Java連接Redis全過程講解

    Java連接Redis全過程講解

    這篇文章主要介紹了Java連接Redis全過程講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Spring Boot Admin 環(huán)境搭建與基本使用詳解

    Spring Boot Admin 環(huán)境搭建與基本使用詳解

    這篇文章主要介紹了Spring Boot Admin 環(huán)境搭建與基本使用,本文主要是對于Spring Boot Admin的基本認識和基本運用,通過本篇博客能夠?qū)pring Boot Admin有一個宏觀認知和能夠快速上手,需要的朋友可以參考下
    2023-08-08
  • java線程并發(fā)blockingqueue類使用示例

    java線程并發(fā)blockingqueue類使用示例

    BlockingQueue是一種特殊的Queue,若BlockingQueue是空的,從BlockingQueue取東西的操作將會被阻斷進入等待狀態(tài)直到BlocingkQueue進了新貨才會被喚醒,下面是用BlockingQueue來實現(xiàn)Producer和Consumer的例子
    2014-01-01

最新評論