Spring 框架通过 **三级缓存机制** 解决单例 Bean 的循环依赖问题,同时确保代理对象(如 AOP 增强对象)的正确生成。以下是三级缓存的区别、作用及设计逻辑的详细分析:
---
### **一、三级缓存的定义与作用**
| **缓存名称** | **存储内容** | **生命周期阶段** | **核心作用** |
|---------------------------|-----------------------------------------------------------------------------|-------------------------------------|-----------------------------------------------------------------------------|
| **一级缓存** `singletonObjects` | 完全初始化后的单例 Bean(包括代理对象) | Bean 完成实例化、属性注入、初始化后 | 提供最终可用的 Bean,避免重复创建 |
| **二级缓存** `earlySingletonObjects` | 提前暴露的 Bean(可能是原始对象或代理对象),已实例化但未完成属性注入和初始化 | Bean 实例化后,但未完成初始化前 | 解决循环依赖,临时保存半成品 Bean,供其他 Bean 注入 |
| **三级缓存** `singletonFactories` | 生成 Bean 的工厂(`ObjectFactory`),用于按需创建 Bean 的早期引用 | Bean 实例化后,但未开始属性注入前 | 延迟生成代理对象,确保循环依赖中注入的始终是增强后的 Bean |
---
### **二、三级缓存的协作流程**
#### **1. 无循环依赖的场景**
• **步骤**:
1. Bean 实例化后,生成原始对象,并注册 `ObjectFactory` 到 **三级缓存**。
2. 完成属性注入和初始化后,将 Bean 存入 **一级缓存**,并清理二、三级缓存。
• **特点**:
三级缓存仅在实例化阶段短暂存在,最终 Bean 直接进入一级缓存。
#### **2. 存在循环依赖的场景**
以 **Bean A 依赖 Bean B,Bean B 依赖 Bean A** 为例:
1. **创建 Bean A**:
• 实例化 A(原始对象),注册 `ObjectFactory` 到 **三级缓存**。
• 开始注入属性时发现依赖 B,触发 B 的创建。
2. **创建 Bean B**:
• 实例化 B(原始对象),注册 `ObjectFactory` 到 **三级缓存**。
• 开始注入属性时发现依赖 A,从 **三级缓存** 获取 A 的 `ObjectFactory`,生成 A 的早期引用(可能是代理对象),存入 **二级缓存**。
3. **完成 Bean B**:
• B 注入 A 的早期引用后,完成初始化并存入 **一级缓存**。
4. **完成 Bean A**:
• A 注入已初始化的 B,完成初始化并存入 **一级缓存**,清理二、三级缓存。
---
### **三、关键设计逻辑**
#### **1. 为什么需要三级缓存?**
• **解决代理对象的唯一性**:
若直接使用二级缓存存储代理对象,当多个 Bean 依赖同一目标 Bean 时,可能导致代理对象重复生成。三级缓存的 `ObjectFactory` 通过延迟生成代理对象,确保全局唯一。
• **避免冗余判断**:
三级缓存通过工厂模式解耦代理生成逻辑,无需在每次获取 Bean 时检查是否需要代理。
#### **2. 与 AOP 代理的协作**
• **代理对象的生成时机**:
在 `ObjectFactory` 的 `getObject()` 方法中,通过 `SmartInstantiationAwareBeanPostProcessor`(如 `AbstractAutoProxyCreator`)动态生成代理对象。
• **示例代码**:
```java
// AbstractAutowireCapableBeanFactory#getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
// 生成代理对象(如需要)
return ((SmartInstantiationAwareBeanPostProcessor) bp).getEarlyBeanReference(bean, beanName);
}
}
return bean; // 无代理则返回原始对象
}
```
---
### **四、示例:循环依赖 + AOP 代理**
#### **场景**
• Bean A 和 Bean B 相互依赖,且 Bean A 被 `@Transactional` 标记(需生成代理)。
#### **流程**
1. **创建 A**:
• 实例化 A(原始对象),注册 `ObjectFactory` 到三级缓存。
• 注入 B 时触发 B 的创建。
2. **创建 B**:
• 实例化 B(原始对象),注册 `ObjectFactory` 到三级缓存。
• 注入 A 时,从三级缓存获取 A 的 `ObjectFactory`,生成代理对象 ProxyA,存入二级缓存。
3. **完成 B**:
• B 注入 ProxyA 后完成初始化,存入一级缓存。
4. **完成 A**:
• A 注入 B 后,检查二级缓存发现已有 ProxyA,直接使用,最终存入一级缓存。
---
### **五、总结**
| **维度** | **一级缓存** | **二级缓存** | **三级缓存** |
|------------------|---------------------------------|--------------------------------------|------------------------------------------|
| **存储内容** | 完全初始化的 Bean | 提前暴露的半成品 Bean(可能为代理) | 生成 Bean 的工厂(用于按需创建代理) |
| **存在意义** | 提供最终可用的 Bean | 临时解决循环依赖的引用问题 | 延迟生成代理,确保单例和增强逻辑正确性 |
| **生命周期** | Bean 完全初始化后 | Bean 实例化后,初始化前 | Bean 实例化后,属性注入前 |
**设计核心**:
通过三级缓存的协作,Spring 在保证单例的前提下,既解决了循环依赖问题,又确保 AOP 代理对象的正确性和唯一性。
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传