Spring無法解決循環(huán)依賴的五種場景分析
一、構造器注入引發(fā)的循環(huán)依賴
1. 問題復現(xiàn)
@Component
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) { // 構造器注入
this.serviceB = serviceB;
}
}
@Component
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) { // 構造器注入
this.serviceA = serviceA;
}
}報錯信息:Requested bean is currently in creation: Is there an unresolvable circular reference?
2. 原理分析
- 三級緩存失效:構造器注入要求在實例化階段完成依賴注入,而此時 Bean 尚未放入三級緩存。
- 生命周期沖突:

3. 解決方案
- 方案 1:將其中一個 Bean 改為 Setter / 字段注入
- 方案 2:使用 `@Lazy` 延遲加載
@Autowired
public ServiceA(@Lazy ServiceB serviceB) {
this.serviceB = serviceB;
}二、原型(Prototype)作用域的循環(huán)依賴
1. 問題復現(xiàn)
@Scope("prototype")
@Component
public class PrototypeA {
@Autowired private PrototypeB b;
}
@Scope("prototype")
@Component
public class PrototypeB {
@Autowired private PrototypeA a;
}2. 原理分析
緩存機制不生效:原型 Bean 不會存入三級緩存,每次請求都創(chuàng)建新實例。
Spring 官方限制:明確說明不處理原型 Bean 的循環(huán)依賴。
3. 解決方案
重構設計:避免原型 Bean 之間的循環(huán)依賴
改用單例:評估是否真的需要原型作用域
三、@Async 注解導致的代理沖突
1. 問題復現(xiàn)
@Service
public class AsyncServiceA {
@Autowired private AsyncServiceB serviceB;
@Async
public void asyncMethod() { /* ... */ }
}
@Service
public class AsyncServiceB {
@Autowired private AsyncServiceA serviceA;
}2. 原理分析
代理時序問題:
@Async通過后置處理器生成代理,可能破壞三級緩存機制。典型錯誤棧:
BeanCreationException: Error creating bean with name 'asyncServiceA': Bean with name 'asyncServiceA' has been injected into other beans [...] in their raw version as part of a circular reference.
3. 解決方案
- 方案 1:對異步方法所在類使用接口代理
@Async
public interface AsyncService {
void asyncMethod();
}
@Service
public class AsyncServiceImpl implements AsyncService { /* ... */ }- 方案 2:在注入點添加
@Lazy
@Autowired @Lazy private AsyncServiceA serviceA;
四、Configuration 類之間的循環(huán)依賴
1. 問題復現(xiàn)
@Configuration
public class ConfigA {
@Autowired private ConfigB configB;
}
@Configuration
public class ConfigB {
@Autowired private ConfigA configA;
}2. 原理分析
配置類加載順序:配置類需要優(yōu)先初始化,無法通過常規(guī)循環(huán)依賴解決。
Spring 限制:
@Configuration類被視為特殊 Bean,其代理機制與普通 Bean 不同。
3. 解決方案
重構配置類:合并相關配置
使用
@DependsOn:明確指定加載順序
@Configuration
@DependsOn("configB")
public class ConfigA { /* ... */ }五、自定義 BeanPostProcessor 引發(fā)的沖突
1. 問題復現(xiàn)
@Component
public class CustomProcessor implements BeanPostProcessor {
@Autowired private ServiceX x; // 依賴其他Bean
}2. 原理分析
處理器加載時序:
BeanPostProcessor需要優(yōu)先初始化,此時普通 Bean 尚未創(chuàng)建。Spring 啟動流程:

3. 解決方案
避免在 BeanPostProcessor 中注入其他 Bean
使用延遲注入
private ObjectProvider<ServiceX> xProvider;
public Object postProcessBeforeInitialization(Object bean, String beanName) {
ServiceX x = xProvider.getIfAvailable();
// ...
}六、終極解決方案工具箱
| 問題類型 | 應急方案 | 根治方案 |
|---|---|---|
| 構造器循環(huán)依賴 | @Lazy 注解 | 改為 Setter 注入 |
| 原型Bean循環(huán)依賴 | 重構作用域 | 引入中間類抽象依賴 |
| AOP代理沖突 | 接口代理模式 | 調整切面作用順序 |
| 配置類循環(huán)依賴 | @DependsOn 指定順序 | 合并配置類 |
| BeanPostProcessor依賴 | ObjectProvider 延遲獲取 | 分離處理器與業(yè)務邏輯 |
結語:跳出循環(huán)依賴的思維陷阱
Spring 的循環(huán)依賴處理機制體現(xiàn)了框架設計的高度智慧,但作為開發(fā)者,最優(yōu)雅的解決方案往往不是技術手段,而是架構設計。通過以下原則可從根本上避免循環(huán)依賴:
單一職責原則:拆分臃腫的 Bean
依賴倒置原則:面向接口編程
層次化設計:Controller -> Service -> Repository 的嚴格分層
以上就是Spring無法解決循環(huán)依賴的五種場景分析的詳細內(nèi)容,更多關于Spring無法解決循環(huán)依賴的資料請關注腳本之家其它相關文章!
相關文章
java多線程編程之使用Synchronized關鍵字同步類方法
JAVA中要想解決“臟數(shù)據(jù)”的問題,最簡單的方法就是使用synchronized關鍵字來使run方法同步,看下面的代碼,只要在void和public之間加上synchronized關鍵字2014-01-01
Spring中Bean的加載與SpringBoot的初始化流程詳解
這篇文章主要介紹了Spring中Bean的加載與SpringBoot的初始化流程詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
springboot post接口接受json時,轉換為對象時,屬性都為null的解決
這篇文章主要介紹了springboot post接口接受json時,轉換為對象時,屬性都為null的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
Java如何基于EasyExcel實現(xiàn)導入數(shù)據(jù)校驗并生成錯誤信息Excel
這篇文章主要介紹了Java如何基于EasyExcel實現(xiàn)導入數(shù)據(jù)校驗并生成錯誤信息Excel,為了優(yōu)化項目中的文件導入功能,考慮構建一個基于EasyExcel的通用Excel導入框架,主要解決導入數(shù)據(jù)的校驗問題,避免業(yè)務代碼中堆積大量校驗邏輯,需要的朋友可以參考下2024-09-09

