spring是如何解决循环依赖的?
时间: 2025-07-11 09:46:27 浏览: 6
<think>好的,用户想了解Spring框架中解决循环依赖的机制。首先,我需要回忆一下Spring如何处理循环依赖的相关知识。记得Spring使用三级缓存来提前暴露尚未完全初始化的Bean,从而解决循环依赖的问题。
首先,循环依赖的定义是什么?多个Bean之间相互依赖,比如A依赖B,B又依赖A,这样就会形成循环。这种情况下,Spring在初始化Bean的时候可能会遇到问题,因为创建A需要B,而创建B又需要A,导致无法完成初始化。
Spring的解决方法主要是通过三级缓存。三级缓存分别是:singletonObjects(一级缓存,存放完全初始化好的Bean)、earlySingletonObjects(二级缓存,存放提前暴露的原始Bean对象)、singletonFactories(三级缓存,存放Bean工厂对象,用于生成原始对象的代理)。当创建Bean A时,首先会通过构造函数创建一个原始对象,并将其工厂放入三级缓存中。然后填充属性时发现需要Bean B,于是开始创建Bean B。在创建Bean B的过程中,同样填充属性时发现需要Bean A,这时会从三级缓存中找到Bean A的工厂,生成原始对象(可能是代理对象)并放入二级缓存,同时移除三级缓存中的工厂。这样Bean B就能成功注入Bean A的原始对象,完成初始化后放入一级缓存。接着Bean A也能从一级缓存中获取Bean B,完成自己的初始化,并放入一级缓存,同时清理二级缓存。
需要注意的是,三级缓存主要解决的是单例作用域的Bean的循环依赖问题。对于原型作用域的Bean,Spring无法解决循环依赖,会直接抛出异常。此外,构造器注入导致的循环依赖也无法通过三级缓存解决,因为构造器注入需要在实例化阶段完成依赖注入,此时Bean还没有被放入缓存中,导致无法解析依赖。
另外,提前暴露对象的概念是关键。Spring在对象实例化后,初始化前,就将对象工厂放入三级缓存,这样当其他Bean需要依赖时,可以通过这个工厂获取到提前暴露的对象,即使它还没有完成属性填充和初始化。
可能还需要提到Spring如何检测循环依赖,以及在不同情况下的处理方式。例如,使用@Lazy注解可以延迟加载依赖,从而避免循环依赖的问题。或者,通过setter注入而不是构造器注入,因为setter注入发生在实例化之后,可以利用三级缓存机制。
用户的问题可能还涉及到为什么使用三级缓存而不是两级。这是因为三级缓存中的ObjectFactory可以处理可能存在AOP代理的情况,确保返回的是合适的代理对象,而不仅仅是原始对象。如果在二级缓存中直接存放原始对象,那么在存在AOP代理的情况下,可能会注入原始对象而不是代理,导致问题。因此,通过ObjectFactory延迟生成代理对象,保证了依赖注入的正确性。
总结一下,Spring解决循环依赖的核心在于三级缓存和提前暴露对象的机制,同时结合Bean的生命周期,在适当的时机处理依赖注入,避免无限循环。需要明确的是,这种机制仅适用于单例Bean,并且不适用于构造器注入的情况。</think>Spring框架通过**三级缓存机制**和**提前暴露未完全初始化的Bean对象**来解决单例Bean的循环依赖问题,核心原理如下:
---
### 一、循环依赖的触发场景
当两个或多个Bean互相依赖时,例如:
- Bean A的构造需要注入Bean B
- Bean B的构造也需要注入Bean A
此时Spring容器在初始化Bean时会陷入“先有鸡还是先有蛋”的死锁状态[^2]。
---
### 二、三级缓存的核心机制
Spring通过以下三个缓存层级解决循环依赖:
1. **一级缓存(singletonObjects)**
存放完全初始化完成的Bean实例,可直接使用[^4]。
2. **二级缓存(earlySingletonObjects)**
存放提前暴露的原始Bean对象(未完成属性填充和初始化)。
3. **三级缓存(singletonFactories)**
存放Bean工厂对象(ObjectFactory),用于生成原始对象的代理(如需要AOP增强)。
---
### 三、解决流程(以Bean A → Bean B → Bean A为例)
1. **创建Bean A**
- 实例化A(调用构造函数)
- 将A的ObjectFactory存入三级缓存
- 开始填充属性时发现依赖Bean B
2. **创建Bean B**
- 实例化B(调用构造函数)
- 将B的ObjectFactory存入三级缓存
- 填充属性时发现依赖Bean A
3. **解决循环依赖**
- 从三级缓存获取A的ObjectFactory,生成原始对象(或代理对象)
- 将A的原始对象存入二级缓存,**移除三级缓存中的A工厂**
- Bean B完成属性注入和初始化,存入一级缓存
4. **完成Bean A初始化**
- 从一级缓存获取已初始化的Bean B
- 完成A的属性注入和初始化
- 将A存入一级缓存,**清除二级缓存中的A对象**
---
### 四、关键限制条件
1. **仅支持单例Bean**
原型(prototype)作用域的Bean无法解决循环依赖,会直接抛出`BeanCurrentlyInCreationException`[^3]。
2. **依赖注入方式限制**
- **构造器注入**无法解决循环依赖(实例化阶段无法提前暴露对象)
- **Setter注入/字段注入**可通过三级缓存机制解决[^4]。
3. **AOP代理的特殊处理**
通过`getEarlyBeanReference()`方法,确保返回的是经过后处理器处理的代理对象(如需要)。
---
### 五、代码示例(简化版Spring实现逻辑)
```java
// 从缓存获取Bean的简化逻辑
protected Object getSingleton(String beanName) {
Object singleton = singletonObjects.get(beanName);
if (singleton == null && isSingletonCurrentlyInCreation(beanName)) {
singleton = earlySingletonObjects.get(beanName);
if (singleton == null) {
ObjectFactory<?> factory = singletonFactories.get(beanName);
if (factory != null) {
singleton = factory.getObject();
earlySingletonObjects.put(beanName, singleton);
singletonFactories.remove(beanName);
}
}
}
return singleton;
}
```
---
阅读全文
相关推荐


















