Spring如何处理循环依赖问题?
时间: 2025-07-10 15:45:25 浏览: 5
<think>好的,我现在需要回答用户关于Spring如何处理循环依赖的问题。首先,我得回忆一下Spring框架中循环依赖的相关知识。循环依赖指的是两个或多个Bean相互依赖,比如Bean A依赖Bean B,而Bean B又依赖Bean A。这种情况下,Spring在初始化Bean的时候可能会出现问题,因为无法确定先创建哪一个。
接下来,我需要思考Spring是如何解决这个问题的。我记得Spring主要使用三级缓存来解决循环依赖。三级缓存分别是singletonObjects、earlySingletonObjects和singletonFactories。这三个缓存分别存储不同阶段的Bean实例。当创建Bean的时候,Spring会先检查缓存中是否存在,如果不存在就开始创建流程。
具体来说,当创建Bean A的时候,Spring会通过构造函数实例化对象,然后将其放入singletonFactories缓存中(此时Bean A还未完成属性填充和初始化)。接着,Spring开始处理Bean A的依赖,发现它需要Bean B。这时候Spring会去创建Bean B,同样实例化Bean B并将其放入singletonFactories。当Bean B处理依赖时,发现需要Bean A,此时Spring会从三级缓存中查找Bean A。具体来说,首先检查singletonObjects,如果没有,检查earlySingletonObjects,最后检查singletonFactories。如果在singletonFactories中找到,就会通过ObjectFactory获取Bean A的早期引用(此时Bean A还未完成初始化),并将这个早期引用放入earlySingletonObjects缓存,同时从singletonFactories中移除。这样Bean B就能完成属性注入,然后Bean B被放入singletonObjects中。接下来,Bean A继续注入Bean B,完成自己的初始化,并被放入singletonObjects,从而解决循环依赖的问题。
需要注意的是,这种三级缓存机制只能解决单例作用域的Bean通过setter或字段注入的循环依赖情况。如果使用构造函数注入,并且循环依赖的Bean都是通过构造函数注入的话,Spring是无法解决的,会抛出BeanCurrentlyInCreationException异常。因为构造函数注入需要先完成构造函数的调用,而此时另一个Bean可能还没有被创建,导致无法满足依赖。
另外,用户可能需要知道为什么需要三级缓存而不是两级。这是因为三级缓存中的singletonFactories存储的是ObjectFactory,它可以处理可能存在AOP代理的情况。当存在AOP代理时,Spring需要确保返回的是代理对象而不是原始对象,而ObjectFactory可以延迟生成代理对象,保证在需要的时候正确返回代理后的Bean。
最后,我需要用简洁的语言将这些步骤整理出来,并给出代码示例来说明循环依赖的情况以及Spring的处理方式。同时,要提醒用户注意循环依赖的最佳实践,尽量避免使用,以保持代码的清晰和可维护性。</think><<
Spring通过**三级缓存机制**解决单例Bean的循环依赖问题,主要支持setter注入和字段注入方式的循环依赖。以下是处理流程:
1. **三级缓存结构**:
- **singletonObjects**:存放完全初始化好的Bean
- **earlySingletonObjects**:存放早期暴露的Bean(已实例化但未完成属性填充)
- **singletonFactories**:存放Bean工厂对象(用于生成早期引用)
2. **处理流程示例**(BeanA → BeanB → BeanA):
```java
// BeanA.java
@Component
public class BeanA {
@Autowired
private BeanB beanB;
}
// BeanB.java
@Component
public class BeanB {
@Autowired
private BeanA beanA;
}
```
**处理步骤**:
1. Spring开始创建BeanA
2. 通过构造函数实例化BeanA(半成品)
3. 将BeanA的ObjectFactory放入singletonFactories(三级缓存)
4. 发现BeanA依赖BeanB,暂停BeanA的初始化
5. 开始创建BeanB
6. 通过构造函数实例化BeanB(半成品)
7. 将BeanB的ObjectFactory放入singletonFactories
8. 发现BeanB依赖BeanA
9. 从三级缓存获取BeanA的早期引用:
- 从singletonFactories取出ObjectFactory
- 生成代理对象(如有AOP)或原始对象
- 将对象升级到earlySingletonObjects(二级缓存)
10. BeanB完成属性注入和初始化
11. BeanB放入singletonObjects(一级缓存)
12. 回到BeanA继续完成属性注入和初始化
13. BeanA放入singletonObjects
3. **限制条件**:
- 仅支持**单例Bean**的循环依赖
- 必须使用**setter/字段注入**(构造函数注入无法解决)
- 需要开启默认的allowCircularReferences配置(默认true)
**为什么需要三级缓存**:
直接使用二级缓存的问题在于无法处理AOP代理。通过ObjectFactory的延迟加载,可以保证代理对象在需要时才被创建,且保持单例特性。
**构造函数注入的异常示例**:
```java
// 会抛出BeanCurrentlyInCreationException
@Component
public class CircleA {
private final CircleB b;
public CircleA(CircleB b) { this.b = b; }
}
@Component
public class CircleB {
private final CircleA a;
public CircleB(CircleA a) { this.a = a; }
}
```
阅读全文
相关推荐


















