Springboot循環(huán)依賴的原因及解決
什么是循環(huán)依賴
循環(huán)依賴(Circular Dependency) 是指兩個(gè)或多個(gè) Bean 相互直接或間接依賴,導(dǎo)致容器無法正常初始化這些 Bean。
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB; // ServiceA 依賴 ServiceB
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA; // ServiceB 依賴 ServiceA
}Spring Boot 基于 Spring 框架,其循環(huán)依賴的處理機(jī)制與 Spring 一致,但在 Spring Boot 2.6+ 版本中默認(rèn)禁止了循環(huán)依賴(通過 spring.main.allow-circular-references=false)。
產(chǎn)生循環(huán)依賴的原因
1.構(gòu)造函數(shù)注入循環(huán)依賴:
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) { // 構(gòu)造函數(shù)注入
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) { // 構(gòu)造函數(shù)注入
this.serviceA = serviceA;
}
}直接報(bào)錯(cuò):構(gòu)造函數(shù)注入的循環(huán)依賴無法解決,容器啟動(dòng)時(shí)拋出
BeanCurrentlyInCreationException。
2.Setter/Field 注入循環(huán)依賴:
在spring中使用@Autowired注解標(biāo)簽進(jìn)行自動(dòng)注入,如果不加以處理,會(huì)出現(xiàn)循環(huán)依賴問題 。
怎么解決循環(huán)依賴
在Springboot2.5以前可以通過三級(jí)緩存解決單例 Bean 的循環(huán)依賴問題。
| 緩存名稱 | 職責(zé) |
|---|---|
singletonObjects | 存放完全初始化好的 Bean(一級(jí)緩存) |
earlySingletonObjects | 存放提前暴露的早期 Bean(二級(jí)緩存) |
singletonFactories | 存放 Bean 的工廠對(duì)象(三級(jí)緩存) |
以最初的ServiceA與ServiceB為例,
創(chuàng)建
ServiceA,通過工廠將其半成品引用存入三級(jí)緩存。ServiceA注入ServiceB,觸發(fā)ServiceB的創(chuàng)建。創(chuàng)建
ServiceB,同樣將其半成品引用存入三級(jí)緩存。ServiceB注入ServiceA時(shí),從三級(jí)緩存中獲取ServiceA的早期引用,完成ServiceB的初始化。ServiceB初始化完成后,ServiceA完成依賴注入,最終初始化。
出現(xiàn)循環(huán)依賴之后的幾個(gè)解決思路:
1.避免循環(huán)依賴(推薦)
重構(gòu)代碼:將公共邏輯抽離到第三個(gè) Bean 中。
使用接口或抽象類:通過面向接口編程解耦具體實(shí)現(xiàn)。
2. 允許循環(huán)依賴(臨時(shí)方案)
在 application.properties 中顯式允許循環(huán)依賴:
# Spring Boot 2.6+ 需要手動(dòng)開啟 spring.main.allow-circular-references=true
這種只適用于Springboot版本在2.6以上的循環(huán)依賴被禁止的情形。
3. 使用 @Lazy 延遲加載
在其中一個(gè)依賴上添加 @Lazy,延遲注入 Bean 的初始化:
@Service
public class ServiceA {
@Lazy
@Autowired
private ServiceB serviceB; // 延遲初始化 ServiceB
}4. 調(diào)整注入方式
優(yōu)先使用 Setter/Field 注入:避免構(gòu)造函數(shù)注入導(dǎo)致的不可解循環(huán)依賴。
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) { // Setter 注入
this.serviceB = serviceB;
}
}使用setter注入
循環(huán)依賴的局限性
構(gòu)造函數(shù)注入無法解決循環(huán)依賴:Spring 容器在創(chuàng)建 Bean 時(shí)需先完成構(gòu)造函數(shù)調(diào)用,此時(shí)依賴的 Bean 尚未初始化。
原型(Prototype)作用域的 Bean:Spring 不管理原型 Bean 的完整生命周期,無法解決其循環(huán)依賴。
AOP 代理問題:如果 Bean 被 AOP 代理(如
@Async、@Transactional),可能導(dǎo)致循環(huán)依賴解決失敗。
總結(jié)
Spring Boot 的循環(huán)依賴本質(zhì)是 Spring 框架的機(jī)制問題,解決核心在于:
理解三級(jí)緩存的工作原理。
優(yōu)先通過代碼設(shè)計(jì)避免循環(huán)依賴。
必要時(shí)合理使用
@Lazy或調(diào)整注入方式。
盡可能在設(shè)計(jì)之初就避免循環(huán)依賴
到此這篇關(guān)于Springboot循環(huán)依賴的原因及解決的文章就介紹到這了,更多相關(guān)Springboot循環(huán)依賴內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Netty服務(wù)端的實(shí)現(xiàn)示例
Netty提供了一套完整的API,用于處理網(wǎng)絡(luò)IO操作,如TCP和UDP套接字,本文主要介紹了SpringBoot整合Netty服務(wù)端的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07
SpringBoot+Mybatis plus實(shí)現(xiàn)多數(shù)據(jù)源整合的實(shí)踐
本文主要介紹了SpringBoot+Mybatis plus實(shí)現(xiàn)多數(shù)據(jù)源整合的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
SpringBoot項(xiàng)目中連接Gauss數(shù)據(jù)庫
本文主要介紹了SpringBoot項(xiàng)目中連接Gauss數(shù)據(jù)庫,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06
Java中快速排序優(yōu)化技巧之隨機(jī)取樣、三數(shù)取中和插入排序
快速排序是一種常用的基于比較的排序算法,下面這篇文章主要給大家介紹了關(guān)于Java中快速排序優(yōu)化技巧之隨機(jī)取樣、三數(shù)取中和插入排序的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Java動(dòng)態(tài)代理和AOP應(yīng)用示例
這篇文章主要介紹了Java動(dòng)態(tài)代理和AOP應(yīng)用,結(jié)合實(shí)例形式分析了java動(dòng)態(tài)代理在AOP面向切面編程中的相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2019-07-07
Spring Cloud Nacos配置修改不生效的解決方法詳解
Nacos作為一個(gè)動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺(tái),廣泛應(yīng)用于Java Spring Cloud項(xiàng)目中,然而,有時(shí)在修改Nacos配置后,這些更改并不會(huì)立即生效,下面我們來看看這樣如何解決吧2025-01-01
java按鈕控件數(shù)組實(shí)現(xiàn)計(jì)算器界面示例分享
本文主要介紹了JAVA通過按鈕數(shù)組來管理界面中的所有按鈕控件,從而使用最少的代碼實(shí)現(xiàn)模擬的計(jì)算器界面2014-02-02

