循环依赖三级缓存 - Spring 如何解决循环依赖
1. 什么是循环依赖
循环依赖(Circular Dependency)是指两个或多个 Bean 之间互相持有对方的引用,形成一种循环引用关系。最常见的表现形式是 A 依赖 B,同时 B 又依赖 A。
A ──depends on──> B
^ │
└────depends on────┘在三层以上的依赖关系中同样可能出现:
A ──depends on──> B
^ │
│ v
D <──depends on─── C1.1 为什么需要解决循环依赖
Spring IoC 容器负责管理 Bean 的完整生命周期,包括实例化(Instantiation)、属性赋值(Populate)、初始化(Initialization)等阶段。如果容器无法处理循环依赖,那么在存在循环引用的情况下,容器将无法完成 Bean 的创建,从而抛出 BeanCurrentlyInCreationException 异常。
在实际的企业级应用中,循环依赖并不少见,尤其是当领域模型之间存在双向关联关系,或者采用分层架构时 Service 层互相调用,都可能导致循环依赖的产生。
1.2 循环依赖的分类
| 类型 | 描述 | Spring 能否解决 |
|---|---|---|
| 构造器注入循环依赖 | 通过构造方法参数引入依赖 | ❌ 无法解决 |
| Setter 注入循环依赖 | 通过 Setter 方法或字段注入 | ✅ 可以解决 |
| prototype 作用域循环依赖 | prototype 类型的 Bean 之间的循环引用 | ❌ 无法解决 |
2. 三级缓存的数据结构
Spring 解决循环依赖的核心机制是 三级缓存(Three-Level Cache),定义在 DefaultSingletonBeanRegistry 类中。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** 一级缓存:singletonObjects,存储完全初始化好的单例 Bean(成品) */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存:earlySingletonObjects,存储提前暴露的早期单例 Bean(半成品) */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三级缓存:singletonFactories,存储用于创建早期 Bean 的 ObjectFactory(工厂) */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 记录当前正在创建中的 Bean 名称集合 */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** 记录已经创建完成的 Bean 名称集合 */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}2.1 每一级缓存的作用
| 缓存级别 | 变量名 | 数据类型 | 作用 |
|---|---|---|---|
| 一级 | singletonObjects | Map<String, Object> | 存储完全初始化好的单例 Bean。Bean 完成实例化 + 属性赋值 + 初始化后放入此处,是 Spring 容器管理单例 Bean 的最终归宿。 |
| 二级 | earlySingletonObjects | Map<String, Object> | 存储提前暴露的早期 Bean 引用。Bean 刚完成实例化(内存已分配、对象已创建),但尚未完成属性赋值和初始化。当从三级缓存中获取到 Bean 后,会将其提升到二级缓存。 |
| 三级 | `singletonFactories** | Map<String, ObjectFactory<?>> | 存储 ObjectFactory 工厂对象。当一个 Bean 需要被提前暴露时,Spring 会注册一个 ObjectFactory 到三级缓存中。这个工厂负责生成 Bean 的早期引用,并且可以在必要时应用 SmartInstantiationAwareBeanPostProcessor 产生 AOP 代理对象。 |
3. getSingleton() 完整流程源码分析
getSingleton() 方法是三级缓存的核心入口,它实现了从缓存中获取 Bean 的完整逻辑。
3.1 getSingleton(String beanName, boolean allowEarlyReference)
这是从缓存中获取 Bean 的核心方法,其流程如下图所示:
┌───────────────┐
│getSingleton() │
└───────┬───────┘
│
▼
┌───────────────────┐
│ 一级缓存查找 │
│ singletonObjects │───────── 命中则直接返回 ──────> ✅ 返回成品 Bean
│ get(key) │
└────────┬──────────┘
│ 未命中
▼
┌───────────────────┐
│ Bean 是否正在创建? │
│ isSingletonCurrently│
│ InCreation(name) │───────── 否 ──────> ❌ 返回 null
└────────┬──────────┘
│ 是
▼
┌───────────────────┐
│ 二级缓存查找 │
│ earlySingletonObjs│───────── 命中则直接返回 ──────> ✅ 返回早期 Bean
│ get(key) │
└────────┬──────────┘
│ 未命中
▼
┌───────────────────┐
│ 是否允许早期引用? │
│ allowEarlyReference│───────── 否 ──────> ❌ 返回 null
└────────┬──────────┘
│ 是
▼
┌─────────────────────────────┐
│ 三级缓存查找 singletonFactories│
│ get(key) │───────── 未命中 ──> ❌ 返回 null
└────────┬────────────────────┘
│ 命中
▼
┌─────────────────────────────┐
│ 执行 ObjectFactory.getObject()│
│ 获取早期 Bean 引用 │
└────────┬────────────────────┘
│
▼
┌─────────────────────────────┐
│ 将 Bean 提升到二级缓存 │
│ earlySingletonObjects.put() │
└────────┬────────────────────┘
│
▼
┌─────────────────────────────┐
│ 移除三级缓存 singletonFac- │
│ tories.remove() │
└────────┬────────────────────┘
│
▼
✅ 返回早期 Bean对应的源码如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 首先尝试从一级缓存(singletonObjects)中获取
Object singletonObject = this.singletonObjects.get(beanName);
// 2. 如果一级缓存中没有,且该 Bean 正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 对缓存集合加锁,保证线程安全
synchronized (this.singletonObjects) {
// 3. 尝试从二级缓存(earlySingletonObjects)中获取
singletonObject = this.earlySingletonObjects.get(beanName);
// 4. 如果二级缓存中也没有,且允许早期引用
if (singletonObject == null && allowEarlyReference) {
// 5. 从三级缓存(singletonFactories)中获取 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 6. 通过 ObjectFactory 获取早期 Bean 引用
// 这步可能会应用 SmartInstantiationAwareBeanPostProcessor
// 产生 AOP 代理对象
singletonObject = singletonFactory.getObject();
// 7. 将早期 Bean 提升到二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
// 8. 移除三级缓存(一个 Bean 的工厂只需要执行一次)
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}3.2 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
这是 createBean() 流程中使用的重载方法,封装了创建单例 Bean 的完整模板:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 对一级缓存加锁
synchronized (this.singletonObjects) {
// 1. 再次检查一级缓存(双重检查锁定模式)
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 2. 检查是否正在销毁中
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(...);
}
// 3. 记录 Bean 正在创建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = true;
try {
// 4. 执行 ObjectFactory.getObject() —— 实际调用 createBean()
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
// 处理异常...
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 5. 移除创建中标记
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 6. 将创建好的 Bean 加入一级缓存,并移除二、三级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 加入一级缓存
this.singletonObjects.put(beanName, singletonObject);
// 移除二级缓存
this.singletonFactories.remove(beanName);
// 移除三级缓存
this.earlySingletonObjects.remove(beanName);
// 标记为已创建
this.alreadyCreated.add(beanName);
}
}4. earlySingletonExposure(早期暴露)机制
早期暴露是 Spring 解决 Setter 注入循环依赖的关键设计。其核心思想是:当一个 Bean 正在创建过程中时,提前将该 Bean 的工厂暴露给容器,使得其他 Bean 在依赖该 Bean 时能够获取到一个"半成品"引用。
4.1 早期暴露的触发时机
早期暴露发生在 AbstractAutowireCapableBeanFactory.doCreateBean() 方法中,位于实例化之后、属性填充之前:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化 Bean(调用构造方法创建 Java 对象)
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
final Object bean = instanceWrapper.getWrappedInstance();
// 2. 判断是否需要早期暴露
// 条件:单例 & 允许循环引用 & Bean 正在创建中
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 3. 将 ObjectFactory 注册到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 4. 属性填充(此处可能触发对其他 Bean 的依赖查找)
populateBean(beanName, mbd, instanceWrapper);
// 5. 初始化 Bean(执行 Aware 方法、PostProcessor、init-method 等)
exposedObject = initializeBean(beanName, exposedObject, mbd);
// ... 后续处理
}protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 仅当一级缓存中还没有该 Bean 时才注册
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
// 同时从二级缓存中移除(确保二级缓存只有在三级缓存执行后才被填充)
this.earlySingletonObjects.remove(beanName);
}
}
}4.2 时序图:Setter 注入循环依赖的完整解决过程
以 A 依赖 B、B 依赖 A 为例:
时序:
A: createBeanInstance() → A 实例化完成(内存对象已创建)
A: addSingletonFactory() → A 将 ObjectFactory 放入三级缓存 ← 早期暴露
A: populateBean() → 开始属性填充,发现依赖 B
A: getBean(B) → 触发 B 的创建
│
▼
B: createBeanInstance() → B 实例化完成
B: addSingletonFactory() → B 将 ObjectFactory 放入三级缓存
B: populateBean() → 开始属性填充,发现依赖 A
B: getBean(A)
│
▼
B: getSingleton(A, true) → 一级缓存无 A → A 正在创建中
→ 二级缓存无 A → 允许早期引用
→ 三级缓存找到 A 的 ObjectFactory
→ 执行 getObject() → 返回 A 的早期引用
→ 将 A 提升到二级缓存,移除三级缓存
│
▼
B: 获得 A 的早期引用 → 完成属性填充
B: initializeBean() → B 初始化完成
B: addSingleton(B) → B 加入一级缓存
│
▼
A: 回到 populateBean() → 此时 B 已经完成,将 B 注入到 A
A: initializeBean() → A 初始化完成
A: addSingleton(A) → A 加入一级缓存,移除二三级缓存5. 为什么三级缓存无法解决构造器注入的循环依赖
5.1 根本原因:构造器注入需要完整的对象
构造器注入要求在调用构造方法时就必须传入依赖对象:
@Component
public class A {
private final B b;
@Autowired
public A(B b) { // 构造 A 时就需要 B
this.b = b;
}
}
@Component
public class B {
private final A a;
@Autowired
public B(A a) { // 构造 B 时就需要 A
this.a = a;
}
}5.2 流程分析:为什么构造器注入会失败
getBean(A) ──> createBeanInstance(A)
│
▼
A 的构造方法需要 B
│
▼
getBean(B) ──> createBeanInstance(B)
│
▼
B 的构造方法需要 A
│
▼
getBean(A) ──> singletonObjects 无 A
earlySingletonObjects 无 A
singletonFactories 无 A ← 关键!
因为 A 还没有完成实例化!
──> 抛出 BeanCurrentlyInCreationException ❌核心原因:三级缓存的早期暴露发生在实例化之后(doCreateBean 中调用 createBeanInstance 之后)。对于构造器注入,在 createBeanInstance 阶段就需要依赖对象,而此时 Bean 尚未实例化完成,三级缓存中还没有注册该 Bean 的 ObjectFactory,因此无法获取到早期引用。
更本质地说,如果 A 的构造方法需要 B,A 连对象都没有被 new 出来,也就不存在"早期对象"可以暴露。三级缓存解决循环依赖的前提是对象已经实例化,只是还没完成属性赋值和初始化。
5.3 解决方案
对于构造器注入的循环依赖,可以采取以下方案:
- 使用
@Lazy注解:延迟代理
@Component
public class A {
private final B b;
@Autowired
public A(@Lazy B b) { // 注入 B 的延迟代理
this.b = b;
}
}- 改用 Setter 注入:将构造器注入改为字段或 Setter 注入
- 使用
@PostConstruct:将依赖的初始化逻辑后置到@PostConstruct方法中
6. AOP 代理与三级缓存的关系
6.1 核心问题:为什么需要三级缓存而不是两级
一个自然的问题是:既然二级缓存 earlySingletonObjects 已经可以存放早期 Bean 供其他 Bean 引用,为什么还需要第三级缓存 singletonFactories?
答案是:AOP 代理。
当一个 Bean 需要被 AOP 代理时,最终放入容器的应该是代理对象,而不是原始对象。如果只有两级缓存(不保留 ObjectFactory),在以下场景中会出现问题:
6.2 getEarlyBeanReference 的作用
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 遍历所有 SmartInstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessors()) {
// 有机会对早期引用进行包装(如产生 AOP 代理)
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}关键方法 getEarlyBeanReference 是 SmartInstantiationAwareBeanPostProcessor 接口定义的:
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
/**
* 获取早期 Bean 引用。Spring 在检测到循环依赖时会调用此方法,
* 允许在 Bean 的早期阶段就生成代理对象。
*/
default Object getEarlyBeanReference(Object bean, String beanName) {
return bean;
}
}6.3 AbstractAutoProxyCreator 的实现
Spring AOP 的核心处理器 AbstractAutoProxyCreator 同时实现了 SmartInstantiationAwareBeanPostProcessor,它在 getEarlyBeanReference 中会创建代理对象:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/** 缓存早期代理引用,避免多次创建 */
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 将原始 Bean 缓存到 earlyProxyReferences
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 创建早期代理对象(如果需要)
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经在 earlyProxyReferences 中存在说明已经做过早期代理
// 这里移除后检查,如果移除了就不再做后续代理
if (this.earlyProxyReferences.remove(cacheKey) != null) {
return bean; // 早期已经代理过,直接返回
}
}
// 正常初始化后代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}6.4 为什么两级缓存不够 —— 场景推演
假设只有两级缓存(singletonObjects + earlySingletonObjects),没有三级缓存,Spring 需要处理 AOP 代理场景:
场景:A 和 B 相互依赖,且 A 需要 AOP 代理。
方案一:实例化后直接创建 AOP 代理放入二级缓存
───────────────────────────────────────────────
A: createBeanInstance() → 原始对象 A0
A: 生成 AOP 代理对象 A_proxy
A: earlySingletonObjects.put(A, A_proxy)
A: populateBean() → B 从二级缓存拿到 A_proxy ✅
A: initializeBean() → 再次执行后置处理器
又生成一个新的代理对象 A_proxy2 ❌
前后不一致!
方案二:实例化后将原始对象放入二级缓存
───────────────────────────────────
A: createBeanInstance() → 原始对象 A0
A: earlySingletonObjects.put(A, A0)
A: populateBean() → B 从二级缓存拿到 A0(原始对象,未代理)❌
B 中持有的是原始对象而不是代理对象
A: initializeBean() → 生成 AOP 代理 A_proxy
A: addSingleton(A_proxy) → 容器中是 A_proxy
但 B 中持有的是 A0 ❌ 不一致!6.5 三级缓存的完整解决方案
有了三级缓存,Spring 通过 ObjectFactory 实现了延迟代理的机制:
A: createBeanInstance() → 原始对象 A0
A: singletonFactories.put(A, factory)
│ factory.getObject() → getEarlyBeanReference() → AbstractAutoProxyCreator
│ 如果检测到需要 AOP 则创建 A_proxy
│ 否则返回 A0
A: populateBean() → 发现依赖 B
│
▼
B: createBeanInstance() → B0
B: singletonFactories.put(B, factory_B)
B: populateBean() → 发现依赖 A
B: getSingleton(A) → 三级缓存找到 A 的 factory
factory.getObject()
│
├─ 调用 getEarlyBeanReference
├─ AbstractAutoProxyCreator 创建 A_proxy(如需)
└─ 返回 A_proxy
│
▼
B: earlySingletonObjects.put(A, A_proxy)
B: singletonFactories.remove(A)
B: 持有 A_proxy ✅ 正确的代理对象
B: initializeBean() → B 完成
B: addSingleton(B) → B 加入一级缓存
│
▼
A: 回到 populateBean() → 注入 B
A: initializeBean()
AbstractAutoProxyCreator.postProcessAfterInitialization()
→ 检查 earlyProxyReferences 发现 A 已经做了早期代理
→ 跳过代理,直接返回原始对象 ✅
│
▼
A: addSingleton(A_proxy) → 一级缓存存储 A_proxy
与 B 中持有的 A_proxy 一致 ✅三级缓存的核心价值:
- 延迟代理的创建时机:直到真正发生循环依赖时才创建代理对象
- 保证全局唯一代理:
AbstractAutoProxyCreator.earlyProxyReferences确保代理对象只创建一次 - 避免不必要的代理创建:如果没有循环依赖,则不会触发早期代理,代理将在初始化后正常创建
7. 源码分析:DefaultSingletonBeanRegistry.getSingleton() 全流程
7.1 类的继承体系
Object
└── SimpleAliasRegistry (别名管理)
└── DefaultSingletonBeanRegistry (单例 Bean 注册表,管理三级缓存)
└── FactoryBeanRegistrySupport (FactoryBean 支持)
└── AbstractBeanFactory (Bean 工厂抽象)
└── AbstractAutowireCapableBeanFactory (自动装配)
└── DefaultListableBeanFactory (默认实现)DefaultSingletonBeanRegistry 是整个三级缓存机制的实现所在,它提供了所有缓存操作的核心方法。
7.2 完整方法一览
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// ════════════════════════════════════════════════
// 三级缓存核心容器
// ════════════════════════════════════════════════
/** 一级缓存:完全初始化好的单例 Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存:早期暴露的单例 Bean(半成品) */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三级缓存:单例 Bean 的 ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 正在创建中的 Bean 名称集合 */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** 已创建完成的 Bean 名称集合 */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
// ════════════════════════════════════════════════
// 核心方法:getSingleton(从缓存获取)
// ════════════════════════════════════════════════
@Override
public Object getSingleton(String beanName) {
// 默认不允许早期引用(非创建过程中的普通查询)
return getSingleton(beanName, true);
}
/**
* 从三级缓存中获取 Bean。
* @param beanName Bean 名称
* @param allowEarlyReference 是否允许早期引用(是否允许从三级缓存获取)
*/
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 获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 提升到二级缓存,移除三级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
/**
* 创建单例 Bean 的模板方法。
* @param beanName Bean 名称
* @param singletonFactory 创建 Bean 的工厂回调
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 检查是否正在销毁
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
// 记录创建前状态
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = true;
try {
// 执行创建(实际调用 createBean)
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException ex) {
// 双重检查
boolean record = recordSuppressedExceptions;
...
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 记录创建后状态
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 加入一级缓存,移除二三级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
// ════════════════════════════════════════════════
// 辅助方法
// ════════════════════════════════════════════════
/** 添加到三级缓存 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
/** 添加到一级缓存,清理二三缓存 */
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.alreadyCreated.add(beanName);
}
}
/** 判断 Bean 是否正在创建中 */
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
/** 创建前的记录 */
protected void beforeSingletonCreation(String beanName) {
if (!this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
/** 创建后的清理 */
protected void afterSingletonCreation(String beanName) {
if (!this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
}7.3 AbstractAutowireCapableBeanFactory.doCreateBean 完整流程
public class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 移除 FactoryBean 缓存中的实例
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// ═══════════════════════════════════════════
// 第 1 步:实例化 Bean
// 通过反射调用构造方法创建 Java 对象
// ═══════════════════════════════════════════
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// ═════════════════════════════════════════════════════
// 第 2 步:早期暴露(MergedBeanDefinitionPostProcessor)
// 允许 BeanPostProcessor 修改 MergedBeanDefinition
// ═════════════════════════════════════════════════════
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// ═════════════════════════════════════════════════════
// 第 3 步:判断是否需要早期暴露
// 条件:单例 & 允许循环引用 & Bean 正在创建中
// 如果满足条件,将 ObjectFactory 注册到三级缓存
// ═════════════════════════════════════════════════════
boolean earlySingletonExposure = (mbd.isSingleton()
&& this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// ═════════════════════════════════════════════════════
// 第 4 步:属性填充
// 如果此时有其他 Bean 依赖当前 Bean,
// 会通过 getSingleton() 从三级缓存中获取早期引用
// ═════════════════════════════════════════════════════
populateBean(beanName, mbd, instanceWrapper);
// ═════════════════════════════════════════════════════
// 第 5 步:初始化 Bean
// 包括 Aware 方法、BeanPostProcessor(前后置)、
// init-method、@PostConstruct 等
// ═════════════════════════════════════════════════════
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// ═════════════════════════════════════════════════════
// 第 6 步:循环依赖校验
// 如果发生了早期暴露,需要校验最终暴露的对象
// 与早期获取的对象是否一致
// ═════════════════════════════════════════════════════
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果从缓存中获取到了早期引用,说明发生了循环依赖
if (exposedObject == bean) {
// 初始化没有改变对象引用,将早期引用作为最终暴露的对象
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 初始化改变了对象引用(如后置处理器返回了不同对象),
// 且存在其他 Bean 依赖当前 Bean,则报错
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(Arrays.asList(dependentBeans));
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] as a raw reference without having been wrapped. " +
"This is a circular reference, but the target bean '" + beanName +
"' is a prototype or has been wrapped by a post-processor...");
}
}
}
}
// 注册 DisposableBean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
}7.4 流程总结
getBean(A)
│
├─ AbstractBeanFactory.doGetBean()
│ ├─ 尝试从 getSingleton(beanName) 获取 → 未命中
│ └─ 标记 A 正在创建中 (beforeSingletonCreation)
│
├─ AbstractAutowireCapableBeanFactory.createBean()
│ └─ doCreateBean(A)
│ ├─ createBeanInstance() → A 实例化完成
│ │
│ ├─ 判断 earlySingletonExposure = true
│ │ └─ addSingletonFactory(A, objectFactory)
│ │ → 三级缓存: singletonFactories[A] = factory
│ │
│ ├─ populateBean(A) → 发现依赖 B
│ │ └─ getBean(B)
│ │ └─ doGetBean(B)
│ │ ├─ getSingleton(B) → 未命中
│ │ ├─ beforeSingletonCreation(B) → 标记 B 创建中
│ │ └─ doCreateBean(B)
│ │ ├─ createBeanInstance() → B 实例化
│ │ ├─ addSingletonFactory(B) → 三级缓存[B]
│ │ ├─ populateBean(B) → 发现依赖 A
│ │ │ └─ getBean(A)
│ │ │ └─ doGetBean(A)
│ │ │ ├─ getSingleton(A, true)
│ │ │ │ └─ 一级: 无
│ │ │ │ 二级: 无
│ │ │ │ 三级: 有! → factory.getObject()
│ │ │ │ → 返回 A 的早期引用(可能代理)
│ │ │ │ 提升到二级缓存
│ │ │ ├─ 返回 A 的早期引用 ✅
│ │ │ └─ A 注入到 B
│ │ ├─ initializeBean(B) → B 初始化
│ │ └─ addSingleton(B) → 一级缓存[B] = B ✅
│ │
│ ├─ populateBean(A) 继续 → 注入 B
│ ├─ initializeBean(A)
│ │ └─ 检查早期代理标记 → 已代理则跳过
│ └─ 循环依赖校验 → earlySingletonReference = A 的早期引用
│ exposedObject == bean → exposedObject = earlySingletonReference
│
└─ addSingleton(A) → 一级缓存[A] = A(代理对象) ✅8. 进阶讨论
8.1 allowRawInjectionDespiteWrapping 参数
allowRawInjectionDespiteWrapping 是 AbstractAutowireCapableBeanFactory 中的一个 boolean 参数,默认值为 false。当设置为 true 时,即使 Bean 的最终版本与早期暴露的版本不一致(例如初始化后产生了新的代理对象),也不会抛出异常。
这个参数在 Spring Boot 的某些自动配置场景下可能被启用,但一般情况下不建议修改。
8.2 不同作用域的循环依赖处理
| 作用域 | Setter 注入 | 构造器注入 | 说明 |
|---|---|---|---|
| singleton | ✅ | ❌ | 三级缓存机制生效 |
| prototype | ❌ | ❌ | 不缓存,每次创建新实例,无法提前暴露 |
| request/session | ❌ | ❌ | 作用域较短,不适用三级缓存 |
对于 prototype 作用域,Spring 根本不会尝试解决循环依赖,检测到循环依赖后直接抛出异常。
8.3 三级缓存与 FactoryBean
FactoryBean 是一个特殊的 Bean,它本身是一个工厂,用于创建其他对象。FactoryBean 自身的创建同样适用三级缓存机制,但通过 FactoryBean 获取对象时(getObject() 方法返回的对象)不受循环依赖影响,因为那是在 Bean 创建完成后才调用的。
8.4 并发安全性
三级缓存的并发安全性通过以下方式保证:
singletonObjects使用ConcurrentHashMap,保证读写可见性getSingleton(String, boolean)中的三级缓存查询操作在synchronized(this.singletonObjects)同步块内执行addSingleton和addSingletonFactory都在synchronized(this.singletonObjects)同步块内执行
这种设计确保了在多线程环境下,每个单例 Bean 在容器中只会被创建一次。
9. 总结
Spring 的三级缓存机制是其 IoC 容器的核心设计之一,通过巧妙的三层缓存结构解决了 Setter 注入场景下的循环依赖问题:
| 缓存级别 | 存储内容 | 作用 |
|---|---|---|
一级 singletonObjects | 完全初始化好的 Bean | 最终成品,供外部获取 |
二级 earlySingletonObjects | 早期暴露的半成品 Bean | 解决循环依赖中的引用一致性 |
三级 singletonFactories | 创建早期 Bean 的 ObjectFactory | 延迟代理创建,支持 AOP |
三级缓存的设计精髓在于将 Bean 的创建过程分解为实例化、属性填充、初始化三个阶段,通过在实例化完成后立即暴露一个 ObjectFactory,让其他依赖此 Bean 的对象能够在 Bean 初始化完成之前就获得其引用(或代理引用),从而打破循环依赖。
但需要谨记的是,这种机制有其适用范围:仅能解决单例、Setter 注入的循环依赖。对于构造器注入或 prototype 作用域的循环依赖,需要通过重构代码或使用 @Lazy 注解等方式来避免。