# Spring源碼分析之如何解決循環依賴
## 目錄
1. [引言](#引言)
2. [什么是循環依賴](#什么是循環依賴)
3. [Spring中的循環依賴場景](#spring中的循環依賴場景)
4. [Spring解決循環依賴的核心設計](#spring解決循環依賴的核心設計)
5. [三級緩存機制詳解](#三級緩存機制詳解)
6. [源碼深度剖析](#源碼深度剖析)
7. [循環依賴的局限性](#循環依賴的局限性)
8. [實際開發中的建議](#實際開發中的建議)
9. [總結](#總結)
## 引言
在Spring框架的使用過程中,循環依賴(Circular Dependency)是一個常見但又容易引發問題的話題。Spring通過巧妙的設計解決了大部分循環依賴場景,但其內部實現機制卻鮮為人知。本文將深入Spring源碼(以5.3.x版本為例),剖析Spring如何通過三級緩存機制解決循環依賴問題。
## 什么是循環依賴
### 基本概念
循環依賴是指兩個或多個Bean相互依賴,形成閉環引用關系:
```java
// 示例1:直接循環依賴
class A {
@Autowired B b;
}
class B {
@Autowired A a;
}
// 示例2:間接循環依賴
class X {
@Autowired Y y;
}
class Y {
@Autowired Z z;
}
class Z {
@Autowired X x;
}
@Service public class ServiceB { private final ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } }
啟動時會拋出`BeanCurrentlyInCreationException`
2. **prototype作用域的循環依賴**
```java
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class PrototypeA {
@Autowired private PrototypeB b;
}
Spring通過三級緩存解決循環依賴問題:
緩存級別 | 名稱 | 存儲內容 |
---|---|---|
第一級緩存 | singletonObjects | 完全初始化好的Bean |
第二級緩存 | earlySingletonObjects | 提前暴露的原始Bean(未填充屬性) |
第三級緩存 | singletonFactories | 單例工廠ObjectFactory |
DefaultSingletonBeanRegistry
:緩存管理的核心類AbstractAutowireCapableBeanFactory
:Bean創建的主要邏輯SmartInstantiationAwareBeanPostProcessor
:AOP代理相關處理graph TD
A[開始創建BeanA] --> B[實例化A]
B --> C[將A的ObjectFactory放入三級緩存]
C --> D[填充A的屬性]
D --> E[發現依賴BeanB]
E --> F[開始創建BeanB]
F --> G[實例化B]
G --> H[將B的ObjectFactory放入三級緩存]
H --> I[填充B的屬性]
I --> J[發現依賴BeanA]
J --> K[從三級緩存獲取A的ObjectFactory]
K --> L[執行getEarlyBeanReference]
L --> M[將A的半成品放入二級緩存]
M --> N[返回A的早期引用給B]
N --> O[完成B的初始化]
O --> P[將B放入一級緩存]
P --> Q[返回B的引用給A]
Q --> R[完成A的初始化]
R --> S[將A放入一級緩存]
DefaultSingletonBeanRegistry#getSingleton
:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 檢查一級緩存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 檢查二級緩存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 檢查三級緩存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
AbstractAutowireCapableBeanFactory#doCreateBean
:
protected Object doCreateBean(/*...*/) {
// 實例化Bean
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
// 將ObjectFactory加入三級緩存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 填充屬性
populateBean(beanName, mbd, instanceWrapper);
// 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}
public void refresh() {
// ...
finishBeanFactoryInitialization(beanFactory);
// ...
}
public void preInstantiateSingletons() {
for (String beanName : beanNames) {
getBean(beanName);
}
}
protected <T> T doGetBean(/*...*/) {
// 檢查緩存
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) {
return (T) sharedInstance;
}
// 創建Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
}
}
當存在AOP代理時,getEarlyBeanReference
會通過AbstractAutoProxyCreator
提前生成代理對象:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
exposedObject = ((SmartInstantiationAwareBeanPostProcessor) bp)
.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
在構造器注入場景下,Bean尚未創建完成就無法放入緩存,導致無法解決循環依賴:
protected BeanWrapper createBeanInstance(/*...*/) {
// 構造器注入會直接嘗試獲取依賴Bean
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, args); // 這里會立即解析參數
}
}
每次獲取prototype bean都會創建新實例,Spring無法管理這種場景下的循環依賴:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanCurrentlyInCreationException:
-Dspring.main.allow-circular-references=true
(Spring Boot 2.6+)代理對象異常:
@Async
等注解的使用Spring通過三級緩存機制(singletonFactories、earlySingletonObjects、singletonObjects)巧妙地解決了單例Bean的setter/field注入循環依賴問題。其核心思想是:提前暴露未完全初始化的Bean引用。理解這一機制對于:
都有重要意義。然而,開發者應當意識到這是框架提供的”安全網”,而非鼓勵循環依賴的設計模式。
附錄:相關源碼類圖
classDiagram
class DefaultSingletonBeanRegistry{
+Map<String,Object> singletonObjects
+Map<String,Object> earlySingletonObjects
+Map<String,ObjectFactory<?>> singletonFactories
+getSingleton(String beanName)
+addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
}
class AbstractAutowireCapableBeanFactory{
+doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args)
+createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)
+populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)
}
DefaultSingletonBeanRegistry <|-- AbstractAutowireCapableBeanFactory
(全文約13,300字,實際字數可能因格式調整略有變化) “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。