Spring的三级缓存原理 笔记251008
Spring的三级缓存原理 笔记251008
- 一级缓存存储: 完成实例化,完成属性注入 的Bean
- 二级缓存存储: 完成实例化,未完成属性注入 的Bean
- 三级缓存存储: Bean的工厂 (Bean还没有实例化)
Spring 的三级缓存是 Singleton 三级缓存体系,用于解决 循环依赖 问题,尤其是 单例 Bean 的循环依赖。它的核心思想是:提前暴露未完全初始化的 Bean 的引用,让其他 Bean 可以先引用它,从而打破循环依赖的死锁。
✅ 三级缓存的结构(DefaultSingletonBeanRegistry)
Spring 的三级缓存是在 DefaultSingletonBeanRegistry
中定义的,分别是:
缓存名称 | 变量名 | 作用 |
---|---|---|
一级缓存 | singletonObjects | 存放 完全初始化好 的单例 Bean(最终成品) |
二级缓存 | earlySingletonObjects | 存放 提前暴露 的单例 Bean(半成品,已实例化但未初始化) |
三级缓存 | singletonFactories | 存放 ObjectFactory,用于生成早期引用(支持 AOP 代理) |
✅ 三级缓存解决循环依赖的流程
假设有两个 Bean:A 和 B,它们互相依赖:
class A {@Autowiredprivate B b;
}class B {@Autowiredprivate A a;
}
步骤如下:
- 创建 A 的实例(构造函数)→ 完成实例化,但未初始化。
- 将 A 的 ObjectFactory 放入三级缓存(
singletonFactories
)。 - 填充 A 的属性 → 发现需要 B。
- 创建 B 的实例 → 完成实例化,未初始化。
- B 填充属性 → 发现需要 A。
- 从三级缓存中获取 A 的 ObjectFactory,调用
getObject()
获取早期引用(可能是代理对象),放入二级缓存。 - B 完成初始化 → 放入一级缓存。
- A 继续填充属性 → 拿到 B 的完整对象。
- A 完成初始化 → 放入一级缓存。
✅ 为什么需要三级缓存?二级不行吗?
- 二级缓存(earlySingletonObjects) 只能存 Bean 的早期引用。
- 三级缓存(singletonFactories) 存的是
ObjectFactory
,可以 延迟创建代理对象,支持 AOP 代理。
如果只有二级缓存,AOP 代理对象必须在实例化后立即创建,这违反了 Spring 的设计原则(代理在初始化后创建)。
三级缓存通过ObjectFactory.getObject()
延迟创建代理,保证了 生命周期一致性。
✅ 总结一句话
三级缓存的核心作用是:通过提前暴露 ObjectFactory,支持循环依赖,并保证 AOP 代理的正确创建时机。
✅ 图示(简化)
singletonObjects(一级) ← 最终成品
↑
earlySingletonObjects(二级) ← 早期引用(从三级缓存拿)
↑
singletonFactories(三级) ← ObjectFactory(延迟创建代理)
✅ 注意
- 仅支持单例 Bean 的循环依赖。
- 原型 Bean(prototype)不支持循环依赖,会直接抛异常。
- 构造器注入的循环依赖无法解决(因为实例化阶段就卡住了)。
需要我帮你画个流程图或贴源码分析吗?
Spring 三级缓存原理详解
1. 循环依赖问题与三级缓存的引入
1.1 循环依赖问题
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowiredprivate UserService userService;
}
上述代码会产生循环依赖:UserService
→ OrderService
→ UserService
1.2 三级缓存的作用
Spring 通过三级缓存机制解决单例 Bean 的循环依赖问题。
2. 三级缓存定义与层次
2.1 三级缓存定义
在 DefaultSingletonBeanRegistry
类中定义:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象(尚未完成属性填充)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的 Bean 名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
2.2 缓存层次说明
缓存级别 | 存储内容 | 作用 |
---|---|---|
一级缓存 | 完全初始化好的 Bean | 提供完整的 Bean 实例 |
二级缓存 | 早期对象(未完成属性填充) | 解决循环依赖,避免重复创建代理 |
三级缓存 | ObjectFactory 工厂对象 | 创建早期引用,支持 AOP 代理 |
3. Bean 创建流程与缓存交互
3.1 Bean 创建的核心流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1. 实例化Object beanInstance = instantiateBean(beanName, mbd);// 2. 添加到三级缓存(解决循环依赖的关键)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));// 3. 属性填充(可能触发循环依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}
3.2 三级缓存的添加时机
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 添加到三级缓存this.singletonFactories.put(beanName, singletonFactory);// 从二级缓存移除this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
}
4. 循环依赖解决流程
4.1 详细解决流程
// 获取 Bean 的核心方法
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. 从三级缓存获取 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过工厂创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,从三级缓存移除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
4.2 循环依赖解决示例
以 UserService
和 OrderService
为例:
// UserService 创建过程
1. 开始创建 UserService
2. 实例化 UserService(原始对象)
3. 将 UserService 的 ObjectFactory 放入三级缓存
4. 属性填充:发现需要 OrderService
5. 开始创建 OrderService// OrderService 创建过程
6. 实例化 OrderService(原始对象)
7. 将 OrderService 的 ObjectFactory 放入三级缓存
8. 属性填充:发现需要 UserService
9. 获取 UserService:- 一级缓存:无- 二级缓存:无 - 三级缓存:找到 UserService 的 ObjectFactory- 通过 ObjectFactory 获取 UserService 的早期引用- 将 UserService 从三级缓存移到二级缓存
10. OrderService 完成属性填充和初始化
11. OrderService 放入一级缓存// 回到 UserService 创建
12. UserService 完成属性填充(注入 OrderService)
13. UserService 完成初始化
14. UserService 放入一级缓存,从二级缓存移除
5. AOP 代理与三级缓存
5.1 代理对象的特殊处理
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
5.2 AOP 代理场景示例
@Service
public class UserService {@Autowiredprivate OrderService orderService;@Transactionalpublic void updateUser() {// 事务方法}
}@Service
public class OrderService {@Autowiredprivate UserService userService; // 这里需要注入代理对象
}
处理流程:
UserService
实例化后,三级缓存中的ObjectFactory
会检查是否需要 AOP 代理- 如果需要代理,
getEarlyBeanReference
返回代理对象 OrderService
注入的是UserService
的代理对象- 保证事务等 AOP 功能正常工作
6. 源码深度解析
6.1 核心源码分析
public class DefaultSingletonBeanRegistry {public Object getSingleton(String beanName) {return getSingleton(beanName, true);}protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 第一级检查:完全初始化的 BeanObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 第二级检查:早期引用singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 第三级检查:ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 升级到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
}
6.2 Bean 创建完整流程
public abstract class AbstractAutowireCapableBeanFactory {protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化 BeanObject beanInstance = instantiateBean(beanName, mbd);// 2. 暴露早期引用(解决循环依赖的关键)boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {// 添加到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性填充(可能触发依赖注入)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);// 5. 处理早期引用暴露if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == beanInstance) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping) {// 处理包装情况}}}return exposedObject;}
}
7. 特殊情况处理
7.1 构造器循环依赖
@Service
public class UserService {private final OrderService orderService;// 构造器注入 - 无法通过三级缓存解决public UserService(OrderService orderService) {this.orderService = orderService;}
}@Service
public class OrderService {private final UserService userService;public OrderService(UserService userService) {this.userService = userService;}
}
结果:构造器循环依赖无法解决,Spring 会抛出 BeanCurrentlyInCreationException
7.2 原型模式的循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class OrderService {@Autowiredprivate UserService userService;
}
结果:原型 Bean 的循环依赖无法解决,因为三级缓存只针对单例 Bean
8. 三级缓存的设计原理
8.1 为什么需要三级缓存?
一级缓存的作用:
- 存储完全初始化好的 Bean
- 提供最终的单例实例
二级缓存的作用:
- 存储早期暴露的对象
- 避免重复创建代理对象
三级缓存的作用:
- 存储创建 Bean 的工厂
- 支持 AOP 代理等后处理器的介入
8.2 三级缓存的必要性
// 如果只有二级缓存,没有三级缓存:
// 在属性填充阶段,如果 Bean 需要被代理,我们无法知道应该返回原始对象还是代理对象// 三级缓存通过 ObjectFactory 延迟决策:
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {// 在这里决定返回原始对象还是代理对象singletonObject = singletonFactory.getObject();
}
9. 实际应用与调试
9.1 调试三级缓存
@Component
public class CacheDebugger implements ApplicationRunner {@Autowiredprivate AbstractApplicationContext context;@Overridepublic void run(ApplicationArguments args) throws Exception {DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) context.getBeanFactory();// 通过反射获取缓存内容printCacheInfo(registry, "singletonObjects");printCacheInfo(registry, "earlySingletonObjects"); printCacheInfo(registry, "singletonFactories");}private void printCacheInfo(DefaultSingletonBeanRegistry registry, String fieldName) {try {Field field = DefaultSingletonBeanRegistry.class.getDeclaredField(fieldName);field.setAccessible(true);Map<?, ?> cache = (Map<?, ?>) field.get(registry);System.out.println(fieldName + ": " + cache.keySet());} catch (Exception e) {e.printStackTrace();}}
}
9.2 循环依赖检测
@Component
public class CircularDependencyDetector {public void detectCircularDependencies(ConfigurableListableBeanFactory beanFactory) {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {try {// 尝试获取 Bean,触发循环依赖检测beanFactory.getBean(beanName);} catch (BeanCurrentlyInCreationException e) {System.out.println("发现循环依赖: " + e.getMessage());}}}
}
10. 性能优化与最佳实践
10.1 避免循环依赖
最佳实践:
- 使用 setter 注入而非构造器注入
- 使用
@Lazy
注解延迟加载 - 重构代码,消除循环依赖
10.2 @Lazy 注解的使用
@Service
public class UserService {@Lazy // 延迟注入,打破循环依赖@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowiredprivate UserService userService;
}
10.3 应用启动参数
# 禁用循环引用(不推荐,但可用于调试)
spring.main.allow-circular-references=false# 允许注入原始 Bean(即使有 AOP 包装)
spring.main.allow-bean-definition-overriding=true
总结
Spring 三级缓存机制的核心要点:
- 解决什么问题:单例 Bean 的循环依赖
- 核心思想:提前暴露未完全初始化的 Bean 引用
- 三级缓存分工:
- 一级缓存:完整的 Bean
- 二级缓存:早期的 Bean 引用
- 三级缓存:Bean 创建工厂
- 关键时机:实例化后、属性填充前添加到三级缓存
- 特殊处理:支持 AOP 代理等后处理器
- 限制条件:无法解决构造器循环依赖和原型 Bean 循环依赖
理解三级缓存原理对于深入掌握 Spring IoC 容器的工作机制、排查循环依赖问题以及进行性能优化都具有重要意义。
1️⃣ 参考 1
Spring 三级缓存原理详解
1. 什么是三级缓存
Spring 的三级缓存是解决循环依赖问题的核心机制。它通过在 Bean 创建的不同阶段将 Bean 对象存储在不同的缓存中,从而允许其他 Bean 在依赖注入时能够获取到尚未完全初始化的 Bean 引用。
2. 三级缓存的具体定义
在 DefaultSingletonBeanRegistry
类中定义了三层缓存:
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 工厂对象,用于创建早期引用private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的 Bean 名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
3. Bean 的创建流程与三级缓存
3.1 Bean 的完整生命周期
// 简化的 Bean 创建流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(调用构造函数)Object beanInstance = createBeanInstance(beanName, mbd, args);// 2. 将 Bean 工厂放入三级缓存(解决循环依赖的关键)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性注入populateBean(beanName, mbd, beanInstanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}
3.2 三级缓存在循环依赖中的工作流程
假设有循环依赖:A → B → A
@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}
创建流程:
-
开始创建 A
// A 开始创建,加入创建中集合 singletonsCurrentlyInCreation.add("a");// 实例化 A 对象 Object a = new A();// 将 A 的 ObjectFactory 放入三级缓存 addSingletonFactory("a", () -> getEarlyBeanReference("a", mbd, a));
-
A 进行属性注入,发现依赖 B
// 在注入 B 时,会调用 getBean("b") // 此时 A 还在创建中,但已经在三级缓存中有工厂对象
-
开始创建 B
singletonsCurrentlyInCreation.add("b"); Object b = new B(); addSingletonFactory("b", () -> getEarlyBeanReference("b", mbd, b));
-
B 进行属性注入,发现依赖 A
// 调用 getBean("a") 获取 A // 发现 A 正在创建中 (singletonsCurrentlyInCreation.contains("a"))// 从三级缓存获取 A 的早期引用 Object aEarly = getSingleton("a", true);
-
获取 A 的早期引用流程
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找(完整 Bean)Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 2. 从二级缓存查找(早期 Bean)singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 3. 从三级缓存获取工厂并创建早期引用ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 将早期引用放入二级缓存,移除三级缓存中的工厂this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject; }
-
B 完成创建
// B 完成属性注入和初始化 // 将 B 放入一级缓存,清除二三级缓存 addSingleton("b", b);
-
A 完成创建
// A 继续完成属性注入(此时 B 已可用) // A 完成初始化,放入一级缓存 addSingleton("a", a);
4. 三级缓存的具体作用
4.1 一级缓存:singletonObjects
- 作用:存放完全初始化好的单例 Bean
- 特点:可直接使用的完整 Bean
- 操作时机:Bean 完全创建完成后放入
4.2 二级缓存:earlySingletonObjects
- 作用:存放早期的 Bean 引用(已实例化但未完成初始化)
- 特点:用于解决循环依赖中的"鸡生蛋"问题
- 操作时机:从三级缓存升级而来
4.3 三级缓存:singletonFactories
- 作用:存放创建早期引用的工厂对象
- 特点:延迟创建,只在需要时生成早期引用
- 核心价值:处理 AOP 代理等特殊情况
5. 为什么需要三级缓存而不是两级?
5.1 处理 AOP 代理的特殊情况
@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowired private A a; // 这里需要的是 A 的代理对象,而不是原始对象
}@Configuration
@EnableAspectJAutoProxy
public class Config {@Beanpublic LoggingAspect loggingAspect() {return new LoggingAspect();}
}
三级缓存的关键代码:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能会返回代理对象而不是原始对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
5.2 三级缓存的必要性
如果只有两级缓存:
- 无法正确处理代理对象的循环依赖
- 可能导致注入的对象与最终对象不一致
三级缓存通过 ObjectFactory
延迟创建,确保:
- 在需要早期引用时才创建
- 能够正确处理 AOP 代理等后处理器
6. 源码分析关键方法
6.1 getSingleton 方法
public Object getSingleton(String beanName) {return getSingleton(beanName, true);
}protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 三级缓存查找逻辑// 1. 一级缓存 → 2. 二级缓存 → 3. 三级缓存
}
6.2 addSingletonFactory 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}
}
6.3 addSingleton 方法
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);}
}
7. 无法解决的循环依赖情况
7.1 构造器循环依赖
@Component
public class A {private final B b;@Autowiredpublic A(B b) { // 构造器注入,无法解决循环依赖this.b = b;}
}@Component
public class B {private final A a;@Autowired public B(A a) { // 构造器注入,无法解决循环依赖this.a = a;}
}
原因:构造器注入时,Bean 还未实例化,无法放入三级缓存。
7.2 Prototype 作用域的循环依赖
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {@Autowiredprivate B b; // Prototype 作用域,无法解决循环依赖
}
8. 总结
Spring 的三级缓存机制:
- 一级缓存:完整 Bean,可直接使用
- 二级缓存:早期 Bean,解决普通循环依赖
- 三级缓存:Bean 工厂,处理 AOP 代理等复杂情况
核心价值:通过分层缓存和延迟创建策略,优雅地解决了 Spring 中的循环依赖问题,同时保证了 Bean 创建的正确性和一致性。
设计思想:空间换时间,通过多级缓存平衡了性能与功能的矛盾,体现了 Spring 框架设计的精妙之处。
2️⃣ 参考 2
Spring 三级缓存原理详解
概述
Spring 的三级缓存是解决循环依赖问题的核心机制。通过三级缓存的设计,Spring 能够在 Bean 创建过程中处理相互依赖的情况。
三级缓存定义
在 DefaultSingletonBeanRegistry
类中定义了三级缓存:
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 ConcurrentHashMap<>(16);// 正在创建中的Bean名称private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
解决循环依赖的流程
场景:A 依赖 B,B 依赖 A
@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}
创建过程详解
1. 开始创建 A
// 步骤1: 检查一级缓存
Object sharedInstance = getSingleton(beanName);
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. 从三级缓存获取ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过ObjectFactory创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,清除三级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
创建 A 的详细步骤:
-
实例化 A
// 调用构造方法创建A实例 instanceWrapper = createBeanInstance(beanName, mbd, args); Object bean = instanceWrapper.getWrappedInstance();
-
将 A 的 ObjectFactory 放入三级缓存
// 在 populateBean 之前执行 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}} }
-
属性注入 - 发现依赖 B
// 在 populateBean 方法中 for (BeanReference beanReference : beanReferences) {// 发现需要注入B,开始获取或创建BString refName = beanReference.getBeanName();Object refBean = getBean(refName); }
2. 开始创建 B
- 实例化 B
- 将 B 的 ObjectFactory 放入三级缓存
- 属性注入 - 发现依赖 A
3. B 获取 A 的流程
// B在属性注入时需要获取A
// 调用 getSingleton("a") 流程:// 1. 一级缓存:无A(A尚未创建完成)
// 2. 二级缓存:无A
// 3. 三级缓存:找到A的ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get("a");
if (singletonFactory != null) {// 通过ObjectFactory获取A的早期引用Object earlyReference = singletonFactory.getObject();// 将A从三级缓存移动到二级缓存this.earlySingletonObjects.put("a", earlyReference);this.singletonFactories.remove("a");return earlyReference;
}
4. 完成创建过程
// B完成创建后,放入一级缓存
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}// A完成属性注入和初始化,放入一级缓存
// 此时B已经在一级缓存中,A可以直接注入完整的B
源码深度解析
getEarlyBeanReference 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能返回代理对象(如AOP)exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
完整的 Bean 创建流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);Object bean = instanceWrapper.getWrappedInstance();// 2. 添加到三级缓存(解决循环依赖)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 属性注入(可能触发循环依赖)Object exposedObject = bean;populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);// 5. 处理循环依赖的早期引用if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}}return exposedObject;
}
特殊情况处理
1. 构造器循环依赖(无法解决)
@Component
public class A {private B b;@Autowiredpublic A(B b) { // 构造器注入this.b = b;}
}@Component
public class B {private A a;@Autowiredpublic B(A a) { // 构造器注入this.a = a;}
}
原因:在构造器阶段就需要完整的依赖对象,而此时 Bean 还未实例化,无法放入三级缓存。
2. 原型模式的循环依赖(无法解决)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {@Autowiredprivate PrototypeB b;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {@Autowiredprivate PrototypeA a;
}
原因:原型模式不缓存 Bean 实例,每次都会创建新实例。
3. 有 AOP 代理的情况
@Component
public class A {@Autowiredprivate B b;public void businessMethod() {// 业务方法}
}@Aspect
@Component
public class LogAspect {@Before("execution(* com.example.A.businessMethod(..))")public void logBefore() {System.out.println("方法执行前日志");}
}
处理流程:
- 创建 A 的原始对象
- 将 A 的 ObjectFactory 放入三级缓存
- ObjectFactory 的
getEarlyBeanReference
方法会调用 AOP 相关的后处理器 - 返回 A 的代理对象作为早期引用
三级缓存总结
缓存级别 | 存储内容 | 作用 | 生命周期 |
---|---|---|---|
一级缓存 | 完整的单例 Bean | 提供最终可用的 Bean | Bean 完全初始化后放入 |
二级缓存 | 早期暴露的 Bean | 避免重复创建代理对象 | 从三级缓存升级而来,最终移入一级缓存 |
三级缓存 | ObjectFactory | 创建早期引用,处理 AOP | Bean 实例化后放入,第一次获取后移除 |
设计思想
- 分离关注点:实例化、依赖注入、初始化分离
- 空间换时间:通过缓存提高性能
- 懒加载思想:ObjectFactory 延迟创建早期引用
- 代理兼容:支持 AOP 等增强功能
最佳实践
- 避免构造器循环依赖
- 优先使用 setter 注入
- 合理设计 Bean 依赖关系
- 了解缓存机制,优化性能
三级缓存机制是 Spring 框架解决循环依赖问题的精妙设计,理解其原理对于深入掌握 Spring IoC 容器至关重要。
3️⃣ 参考 3
Spring 三级缓存原理详解
1. 三级缓存概述
Spring 的三级缓存是解决循环依赖问题的核心机制。所谓循环依赖,就是两个或多个 Bean 相互依赖,形成依赖闭环。
2. 三级缓存定义
在 DefaultSingletonBeanRegistry
类中定义了三级缓存:
public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例Bean(完全初始化好的Bean)private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例Bean(已实例化但未初始化的Bean)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的Bean名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
3. Bean 创建流程与三级缓存
3.1 Bean 创建的基本流程
// 简化版的Bean创建流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(分配内存空间)Object bean = instanceWrapper.getWrappedInstance();// 2. 将Bean工厂放入三级缓存(解决循环依赖的关键)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 3. 属性注入(可能触发依赖Bean的创建)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化(调用初始化方法)exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}
4. 循环依赖解决过程
4.1 场景:A 依赖 B,B 依赖 A
@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}
4.2 详细解决流程
// 创建A的过程
1. getBean("A")→ 从一级缓存singletonObjects获取A,不存在→ 标记A为创建中:singletonsCurrentlyInCreation.add("A")→ 实例化A对象(此时A是个半成品,b=null)2. 将A的ObjectFactory放入三级缓存addSingletonFactory("A", () -> getEarlyBeanReference("A", mbd, a))3. 属性注入:发现A依赖B→ getBean("B")// 创建B的过程
4. getBean("B")→ 从一级缓存获取B,不存在→ 标记B为创建中:singletonsCurrentlyInCreation.add("B")→ 实例化B对象5. 将B的ObjectFactory放入三级缓存addSingletonFactory("B", () -> getEarlyBeanReference("B", mbd, b))6. 属性注入:发现B依赖A→ getBean("A")7. 再次获取A→ 一级缓存:没有→ 二级缓存:没有→ 三级缓存:找到A的ObjectFactory→ 调用ObjectFactory.getObject()获取A的早期引用→ 将A从三级缓存移到二级缓存→ 返回A的早期引用给B8. B完成属性注入(此时B持有A的早期引用)
9. B完成初始化,放入一级缓存→ 从三级缓存移除B的ObjectFactory→ 从二级缓存移除B(如果有)→ singletonObjects.put("B", b)// 回到A的创建
10. A获得B的完整实例,完成属性注入
11. A完成初始化,放入一级缓存→ 从三级缓存移除A的ObjectFactory→ 从二级缓存移除A→ singletonObjects.put("A", a)
4.3 缓存状态变化时序图
时间轴: t1 t2 t3 t4 t5 t6
创建A: 开始实例化 → 放入三级缓存 → 属性注入需要B → → 完成初始化
创建B: 开始实例化 → 放入三级缓存 → 属性注入需要A → 完成初始化
三级缓存A: 空 有A工厂 有A工厂 空 空
二级缓存A: 空 空 空 有A早期引用 空
一级缓存A: 空 空 空 空 有A完整Bean
5. 源码关键方法解析
5.1 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. 从三级缓存获取ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 创建早期引用singletonObject = singletonFactory.getObject();// 5. 移到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
5.2 addSingletonFactory 方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 放入三级缓存this.singletonFactories.put(beanName, singletonFactory);// 清理二级缓存this.earlySingletonObjects.remove(beanName);}}
}
5.3 getEarlyBeanReference 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能返回代理对象(如AOP代理)exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
6. 特殊情况处理
6.1 构造器循环依赖(无法解决)
@Component
public class A {private B b;@Autowiredpublic A(B b) { // 构造器注入,无法解决循环依赖this.b = b;}
}@Component
public class B {private A a;@Autowiredpublic B(A a) { // 构造器注入,无法解决循环依赖this.a = a;}
}
原因:在构造器注入时,Bean 还没有实例化,无法将 ObjectFactory 放入三级缓存。
6.2 原型(Prototype)作用域的循环依赖(无法解决)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {@Autowiredprivate PrototypeB b;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {@Autowiredprivate PrototypeA a;
}
原因:原型 Bean 不缓存,每次都会创建新实例。
7. 与 AOP 的协同工作
7.1 代理对象的处理
@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;@Transactional // 需要AOP代理public void method() {// ...}
}@Component
public class ServiceB {@Autowiredprivate ServiceA serviceA; // 这里注入的应该是代理对象
}
处理过程:
- 在
getEarlyBeanReference
方法中,AbstractAutoProxyCreator
会创建代理对象 - 三级缓存中存储的是能返回代理对象的 ObjectFactory
- 当发生循环依赖时,返回的是代理对象而不是原始对象
8. 总结
8.1 三级缓存的作用
- 一级缓存:存储完全初始化好的 Bean,可直接使用
- 二级缓存:存储早期的 Bean 引用,用于避免重复创建代理对象
- 三级缓存:存储 Bean 工厂,用于创建早期引用并处理 AOP 代理
8.2 解决循环依赖的条件
- 必须是单例 Bean
- 不能是构造器注入(必须是字段注入或 setter 注入)
- 依赖的 Bean 必须能被提前暴露
8.3 设计思想
Spring 的三级缓存机制体现了"空间换时间"和"关注点分离"的设计思想,通过缓存不同状态的 Bean 来优雅地解决复杂的循环依赖问题,同时保证了 Bean 创建过程的正确性和性能。
4️⃣ 参考 4
Spring 三级缓存原理详解
1. 循环依赖问题
1.1 什么是循环依赖
@Service
public class AService {@Autowiredprivate BService bService;
}@Service
public class BService {@Autowiredprivate AService aService;
}
这种相互依赖的情况就是循环依赖。
2. 三级缓存结构
Spring 通过三级缓存来解决循环依赖问题:
2.1 三级缓存定义
public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象(尚未填充属性)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的 Beanprivate final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
3. Bean 创建流程与三级缓存
3.1 Bean 创建的主要步骤
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化Object bean = instanceWrapper.getWrappedInstance();// 2. 添加到三级缓存(解决循环依赖的关键)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 属性填充(可能触发依赖 Bean 的创建)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}
3.2 三级缓存的具体作用
一级缓存:singletonObjects
- 作用:存放完全初始化好的单例 Bean
- 时机:Bean 完成所有初始化后放入
二级缓存:earlySingletonObjects
- 作用:存放早期的 Bean 引用(已实例化但未完成属性注入)
- 时机:从三级缓存中获取到 Bean 后升级到此缓存
三级缓存:singletonFactories
- 作用:存放 Bean 的 ObjectFactory,用于创建早期引用
- 时机:Bean 实例化后立即放入
4. 循环依赖解决流程
4.1 AService 和 BService 的创建过程
// 创建 AService 的流程
1. beforeSingletonCreation("aService") // 标记 aService 正在创建
2. instance = createBeanInstance() // 实例化 AService 对象
3. addSingletonFactory("aService", () -> getEarlyBeanReference(...)) // 加入三级缓存// 此时三级缓存状态:
// singletonFactories: {"aService": ObjectFactory}4. populateBean("aService") // 开始属性注入
5. 发现需要 bService,调用 getBean("bService")// 创建 BService 的流程
6. beforeSingletonCreation("bService") // 标记 bService 正在创建
7. instance = createBeanInstance() // 实例化 BService 对象
8. addSingletonFactory("bService", () -> getEarlyBeanReference(...)) // 加入三级缓存9. populateBean("bService") // 开始属性注入
10. 发现需要 aService,调用 getBean("aService")// 关键步骤:获取 aService
11. getSingleton("aService") 调用过程:- 一级缓存:没有找到 ✓- 二级缓存:没有找到 ✓ - 三级缓存:找到 ObjectFactory ✓- 调用 ObjectFactory.getObject() 获取早期引用- 将 aService 从三级缓存升级到二级缓存- 返回 aService 的早期引用// 继续 BService 的创建
12. 将 aService 的早期引用注入到 BService
13. BService 完成初始化,放入一级缓存// 继续 AService 的创建
14. 将完整的 BService 注入到 AService
15. AService 完成初始化,放入一级缓存
4.2 源码中的关键方法
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;
}
5. 为什么需要三级缓存?
5.1 代理对象的处理
三级缓存主要为了解决 AOP 代理对象的循环依赖问题。
// ObjectFactory 的实现
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能会返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
5.2 两级缓存的问题
如果只有两级缓存,会出现的问题:
- 无法正确处理代理对象的循环依赖
- 可能产生多个不同的代理对象实例
6. 特殊情况处理
6.1 构造器循环依赖(无法解决)
@Service
public class AService {private final BService bService;@Autowiredpublic AService(BService bService) {this.bService = bService;}
}@Service
public class BService {private final AService aService;@Autowiredpublic BService(AService aService) {this.aService = aService;}
}
结果:Spring 会抛出 BeanCurrentlyInCreationException
6.2 原型模式的循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class AService {@Autowiredprivate BService bService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class BService {@Autowiredprivate AService aService;
}
结果:Spring 会抛出 BeanCurrentlyInCreationException
7. 源码调试示例
7.1 调试关键点
// 断点设置位置:
1. DefaultSingletonBeanRegistry.getSingleton()
2. AbstractAutowireCapableBeanFactory.doCreateBean()
3. AbstractAutowireCapableBeanFactory.createBeanInstance()
4. AbstractAutowireCapableBeanFactory.populateBean()// 观察三级缓存的变化:
- singletonObjects: 一级缓存
- earlySingletonObjects: 二级缓存
- singletonFactories: 三级缓存
- singletonsCurrentlyInCreation: 正在创建的 Bean
8. 总结
8.1 三级缓存的核心价值
- 解决循环依赖:通过提前暴露对象引用
- 保证单例:确保整个过程中只有一个 Bean 实例
- 支持 AOP:正确处理代理对象的循环依赖
8.2 使用建议
- 避免构造器循环依赖:使用 @Autowired 字段注入或 setter 注入
- 理解作用域限制:只有单例 Bean 能解决循环依赖
- 合理设计架构:尽量减少循环依赖,提高代码可维护性
8.3 核心流程图
Bean 实例化 → 加入三级缓存 → 属性注入 → 遇到依赖↓
依赖 Bean 创建 → 需要原始 Bean → 从三级缓存获取↓
ObjectFactory.getObject() → 可能返回代理对象 → 升级到二级缓存↓
依赖 Bean 完成创建 → 原始 Bean 继续初始化 → 升级到一级缓存
通过三级缓存机制,Spring 优雅地解决了单例 Bean 的循环依赖问题,同时保证了 Bean 创建过程的正确性和一致性。
5️⃣ 参考 5
Spring的三级缓存是Spring框架为解决单例Bean循环依赖问题而设计的核心机制,通过分阶段缓存Bean实例的不同状态,确保在依赖注入过程中避免重复创建和死循环。以下是其原理的详细说明:
一、三级缓存的组成
Spring的三级缓存由三个Map结构组成,分别存储Bean在不同生命周期阶段的状态:
-
一级缓存(SingletonObjects)
- 作用:存储已完全初始化好的单例Bean。
- 特点:Bean已完成所有依赖注入和初始化(如
@Autowired
、@PostConstruct
等),可直接供其他Bean使用。 - 数据结构:
ConcurrentHashMap<String, Object>
,线程安全。
-
二级缓存(EarlySingletonObjects)
- 作用:存储已实例化但未完全初始化的Bean(半成品Bean)。
- 特点:Bean已完成实例化(如通过构造器或工厂方法创建),但尚未完成属性注入和初始化。
- 使用场景:当Bean存在循环依赖时,提前暴露半成品Bean供其他Bean引用。
- 数据结构:
HashMap<String, Object>
,非线程安全(因一级缓存已保证线程安全)。
-
三级缓存(SingletonFactories)
- 作用:存储Bean的工厂对象(
ObjectFactory
),用于动态生成代理对象或原始对象。 - 特点:
- 解决AOP代理问题:若Bean需要被代理(如
@Transactional
、@Async
等),工厂对象可按需生成代理对象或原始对象。 - 避免重复创建:通过Lambda表达式延迟对象生成,确保单例Bean的唯一性。
- 解决AOP代理问题:若Bean需要被代理(如
- 数据结构:
HashMap<String, ObjectFactory<?>>
,存储工厂接口。
- 作用:存储Bean的工厂对象(
二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:
-
创建Bean A
- Spring从一级缓存查找Bean A,未找到。
- 创建Bean A的实例(调用构造器),并将其放入三级缓存(存储工厂对象)。
- 开始属性注入,发现依赖Bean B。
-
创建Bean B
- Spring从一级缓存查找Bean B,未找到。
- 创建Bean B的实例,并将其放入三级缓存。
- 开始属性注入,发现依赖Bean A。
-
解决Bean A的循环依赖
- Spring从一级缓存查找Bean A,未找到;从二级缓存查找,未找到。
- 从三级缓存获取Bean A的工厂对象,调用
getObject()
生成半成品Bean A(可能是代理对象)。 - 将半成品Bean A放入二级缓存,并从三级缓存移除。
- 将半成品Bean A注入Bean B。
-
完成Bean B的初始化
- Bean B完成属性注入和初始化(如调用
init-method
)。 - 将完全初始化的Bean B放入一级缓存,并从二级缓存移除。
- Bean B完成属性注入和初始化(如调用
-
完成Bean A的初始化
- Spring继续Bean A的属性注入,从一级缓存获取完全初始化的Bean B。
- Bean A完成初始化,放入一级缓存,并从二级缓存移除。
三、三级缓存的核心作用
-
解决循环依赖
- 通过提前暴露半成品Bean,打破循环依赖的死锁。
- 例如:Bean A依赖Bean B,Bean B依赖Bean A时,三级缓存确保Bean A的半成品可被Bean B引用。
-
支持AOP代理
- 三级缓存的工厂对象可按需生成代理对象,避免代理对象与原始对象冲突。
- 例如:若Bean A需要被代理,工厂对象会返回代理对象而非原始对象。
-
保证单例唯一性
- 通过一级缓存确保每个Bean仅初始化一次,避免重复创建。
-
提升性能
- 缓存半成品Bean减少重复实例化开销,加速Bean创建过程。
四、源码解析
关键方法位于DefaultSingletonBeanRegistry
类中:
-
getSingleton(String beanName, boolean allowEarlyReference)
- 按一级缓存→二级缓存→三级缓存的顺序查找Bean。
- 若从三级缓存获取,则调用工厂对象生成Bean,并升级到二级缓存。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject; }
-
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
- 将Bean的工厂对象存入三级缓存,用于后续循环依赖处理。
五、限制与注意事项
-
仅支持单例Bean
- 多例(Prototype)Bean无法通过三级缓存解决循环依赖,因每次请求都会创建新实例。
-
构造器注入的局限性
- 若循环依赖通过构造器注入(如
public A(B b) {}
),三级缓存无法解决,会抛出BeanCurrentlyInCreationException
。 - 解决方案:改用Setter注入或字段注入。
- 若循环依赖通过构造器注入(如
-
AOP代理的兼容性
- 若Bean未被代理,三级缓存可简化为二级缓存(直接存储半成品Bean)。
- 但为统一处理代理场景,Spring始终使用三级缓存。
6️⃣ 参考 6
Spring三级缓存原理详解
Spring三级缓存是Spring框架解决Bean循环依赖问题的核心机制,通过"提前暴露半成品Bean"的方式,确保即使存在循环依赖也能正确初始化Bean。
三级缓存结构
-
一级缓存 (singletonObjects)
- 存储完全初始化后的单例Bean
- ConcurrentHashMap实现,Key为beanName
- 是最终可以被使用的Bean实例
-
二级缓存 (earlySingletonObjects)
- 存储已实例化但未初始化的"早期引用"
- HashMap实现
- 用于解决AOP代理问题
-
三级缓存 (singletonFactories)
- 存储ObjectFactory函数式接口
- 通过getObject()方法生成代理对象
- 用于在Bean创建过程中提前暴露未完成的Bean
工作流程
当Spring容器需要获取一个Bean时,会按照以下顺序查询缓存:
先查一级缓存 → 无
查二级缓存 → 无
查三级缓存 → 执行ObjectFactory
循环依赖解决示例
以A依赖B,B依赖A的循环依赖为例:
- Spring先实例化A(A是半成品,属性未注入)
- 为A创建ObjectFactory,并放入三级缓存
- A需要注入B,开始实例化B
- B需要注入A,此时在三级缓存中找到A的ObjectFactory
- 通过ObjectFactory获取A的半成品对象
- B完成初始化,放入一级缓存
- A继续完成初始化,放入一级缓存
重要特性与限制
-
适用范围:
- 仅适用于Singleton作用域的Bean
- 无法解决构造器注入的循环依赖(会抛出BeanCurrentlyInCreationException异常)
-
AOP代理处理:
- 在getEarlyBeanReference方法中,如果有AOP配置,会在此生成代理对象
-
多线程问题:
- 三级缓存机制在多线程环境下仍可能出现NPE问题
为什么需要三级缓存?
- 如果只用两级缓存(一级和二级),在AOP场景下会导致问题
- 三级缓存提供了一个"工厂",可以在需要时生成代理对象,避免了在二级缓存中存储代理对象的问题
三级缓存的意义
通过三级缓存机制,Spring实现了:
- 提前暴露未完成的Bean
- 解决循环依赖问题
- 保证Bean创建过程的一致性和正确性
- 提高Bean实例的创建效率,避免重复创建
常见误区
- 三级缓存不是为了解决所有循环依赖问题,而是解决Setter注入方式的循环依赖
- 构造器注入的循环依赖无法通过三级缓存解决
- 原型Bean的循环依赖问题无法通过三级缓存解决
理解Spring三级缓存原理对深入掌握IoC容器工作原理至关重要,也是Java开发者必须掌握的核心知识点之一。
7️⃣ 参考 7
在Spring中,三级缓存是解决单例Bean循环依赖问题的核心机制。循环依赖指多个Bean之间互相依赖(如A依赖B,B依赖A),若不特殊处理,会导致Bean创建时陷入无限循环。三级缓存通过分层缓存设计,实现了Bean的“提前暴露”,从而打破循环依赖。
一、三级缓存的定义
Spring通过三个缓存(Map结构)存储单例Bean的不同状态,按“完成度”从高到低分为:
-
一级缓存(singletonObjects)
类型:Map<String, Object>
作用:存储完全初始化完成的单例Bean(已实例化、属性注入、初始化方法执行完毕)。这是最终供用户使用的Bean。 -
二级缓存(earlySingletonObjects)
类型:Map<String, Object>
作用:存储提前暴露的早期Bean实例(已实例化,但未完成属性注入和初始化)。这些实例可能是原始对象,也可能是经过AOP代理的对象(若Bean需要被代理)。 -
三级缓存(singletonFactories)
类型:Map<String, ObjectFactory<?>>
作用:存储Bean的工厂对象(ObjectFactory)。工厂的作用是在需要时生成早期Bean实例(可能触发AOP代理创建),避免提前生成代理对象造成资源浪费。
二、三级缓存的工作流程(以A依赖B,B依赖A为例)
-
创建Bean A的流程
- 步骤1:Spring启动时,触发Bean A的创建,先检查一级缓存(singletonObjects),若不存在则继续。
- 步骤2:实例化A(调用构造器生成原始对象),此时A尚未完成属性注入和初始化。
- 步骤3:将A的工厂对象(ObjectFactory)放入三级缓存(singletonFactories)。工厂的逻辑是:若A需要AOP代理,则生成代理对象;否则返回原始对象。
- 步骤4:开始为A注入属性,发现依赖B,此时触发Bean B的创建。
-
创建Bean B的流程
- 步骤1:检查一级缓存,B不存在,继续创建。
- 步骤2:实例化B,将B的工厂放入三级缓存。
- 步骤3:为B注入属性,发现依赖A,开始查找A。
-
解决B对A的依赖
- 步骤1:查找A时,先查一级缓存(A未完成,无),再查二级缓存(无),最后查三级缓存(存在A的工厂)。
- 步骤2:通过A的工厂生成A的早期实例(若A需要代理,则此处生成代理对象),并将该实例从三级缓存移至二级缓存(earlySingletonObjects)。
- 步骤3:将A的早期实例注入B,B完成属性注入和初始化,放入一级缓存(singletonObjects)。
-
完成A的创建
- B创建完成后,回到A的属性注入步骤,将B从一级缓存中取出并注入A。
- A完成属性注入和初始化,放入一级缓存(singletonObjects),同时从二级缓存中移除A的早期实例。
三、为什么需要三级缓存?
核心原因是处理AOP代理场景下的循环依赖:
- 若仅用两级缓存(一级+二级),提前暴露的Bean只能是原始对象。但如果Bean需要AOP代理(如被
@Transactional
注解),最终应使用代理对象,而原始对象注入后会导致不一致(注入的是原始对象,最终容器中是代理对象)。 - 三级缓存的工厂(ObjectFactory)实现了“延迟生成代理”:只有当循环依赖发生时,才会通过工厂生成代理对象并放入二级缓存,避免了无循环依赖时不必要的代理创建,同时保证注入的是正确的代理对象。
四、适用范围与限制
- 仅支持单例Bean:原型Bean(
scope="prototype"
)每次创建都是新实例,无法缓存,因此循环依赖会直接报错。 - 不支持构造器循环依赖:若A的构造器依赖B,B的构造器依赖A,由于实例化(构造器调用)前无法生成工厂对象,三级缓存无法生效,会报错。
- 依赖必须通过setter注入或字段注入:只有实例化后(构造器执行完),才能通过工厂提前暴露Bean,因此构造器注入无法解决循环依赖。
总结:三级缓存通过“提前暴露工厂→按需生成早期实例→最终完善Bean”的流程,既解决了单例Bean的循环依赖问题,又兼顾了AOP代理的正确性,是Spring容器设计的精妙之处。
8️⃣ 参考 8
Spring三级缓存原理详解
Spring的三级缓存机制是解决单例Bean循环依赖的核心设计,其工作原理如下:
1. 三级缓存的定义
// Spring容器中的三级缓存
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存:完整Bean
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 二级缓存:半成品Bean
Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(); // 三级缓存:Bean工厂
2. 解决循环依赖的流程(以A→B→A为例)
-
创建A实例
- 实例化A(调用构造函数),此时A是原始对象
- 将A的
ObjectFactory
存入三级缓存:singletonFactories.put("a", () -> getEarlyBeanReference(a))
-
填充A的属性
- 发现A依赖B,触发B的创建
- 此时A仍处于半成品状态(未完成属性注入)
-
创建B实例
- 实例化B,将B的
ObjectFactory
存入三级缓存 - 填充B属性时发现依赖A
- 实例化B,将B的
-
解决依赖闭环
- B从三级缓存获取A的
ObjectFactory
- 执行
getEarlyBeanReference()
生成A的早期引用(可能是代理对象) - 将A从三级缓存移除,存入二级缓存:
earlySingletonObjects.put("a", proxyA)
- B从三级缓存获取A的
-
完成初始化
- B获得A的代理对象,完成属性注入→B初始化完成→存入一级缓存
- A获得B的完整实例,完成属性注入→A初始化完成→存入一级缓存
3. 三级缓存的核心作用
缓存级别 | 存储内容 | 核心目的 |
---|---|---|
一级缓存 | 完整Bean(singletonObjects ) | 提供最终可用的Bean |
二级缓存 | 半成品Bean(earlySingletonObjects ) | 暂存早期暴露的对象 |
三级缓存 | Bean工厂(ObjectFactory ) | 动态创建代理对象 |
关键设计亮点:
- 三级缓存通过
ObjectFactory
实现延迟处理,在需要注入时才执行AOP代理逻辑 - 避免直接暴露原始对象,确保注入的是最终代理对象(如
@Transactional
生效)
4. 应用限制
依赖类型 | 是否支持 | 原因 |
---|---|---|
Setter/字段注入 | ✅ 支持 | 可提前暴露半成品Bean |
构造器注入 | ❌ 不支持 | 实例化前无法暴露引用 |
原型(Prototype)Bean | ❌ 不支持 | Spring不缓存原型Bean |
5. 典型案例分析
场景:AService需注入BService,BService需注入AService(二者都有@Async
代理)
解决:
- AService实例化后,存入三级缓存(含生成代理的
ObjectFactory
) - BService创建时通过
ObjectFactory.getObject()
获取A的代理对象 - 避免直接注入原始对象导致AOP失效
三级缓存的本质是:通过函数式编程分离实例化与代理过程,打破循环依赖的死锁
9️⃣ 参考 9
Spring的三级缓存机制是其解决单例Bean循环依赖问题的核心设计,主要通过分层缓存和提前暴露不完全初始化的Bean来实现。下面用一个表格帮你快速梳理这三级缓存:
缓存层级 | 名称 | 存储内容 | 主要作用 |
---|---|---|---|
一级缓存 | singletonObjects | 完全初始化完成的单例Bean | 提供最终可用的Bean,是正式的“单例池” |
二级缓存 | earlySingletonObjects | 早期暴露的Bean(已实例化,但未完成初始化) | 解决循环依赖,避免多次从工厂创建实例 |
三级缓存 | singletonFactories | 创建Bean的工厂对象 (ObjectFactory ) | 用于延迟创建早期引用,支持AOP代理 |
🔧 三级缓存如何解决循环依赖
我们以经典的循环依赖为例:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A。
⚙️ 为何需要三级缓存?
你可能会问,为什么不能只用二级缓存?关键在于 AOP代理。
如果只有二级缓存(直接存储对象),那么每次依赖注入时,注入的都将是原始的Bean对象。但如果这个Bean最终需要被AOP代理,那么就会出现问题:依赖注入的是原始对象,而正式使用的却是代理对象,这显然是不一致的。
三级缓存通过存入一个ObjectFactory
工厂来解决这个问题。这个工厂(通常通过getEarlyBeanReference
方法)能够在被调用时,智能地判断是否需要返回代理对象,从而保证最终注入的早期引用与最终完成的Bean(可能是代理对象)是同一个对象。
⚠️ 注意事项
Spring的三级缓存机制很强大,但也有其局限性:
- 仅适用于单例Bean:原型(prototype)作用域的Bean无法使用三级缓存解决循环依赖。
- 不支持构造器循环依赖:如果循环依赖是通过构造器注入(Constructor Injection)方式发生的,三级缓存也无法解决。因为Spring必须通过构造器创建对象实例,在实例化之前无法提前暴露引用,会直接抛出
BeanCurrentlyInCreationException
异常。 - 设计警示:虽然Spring提供了这个机制,但从设计角度来说,应用程序中出现循环依赖通常是不推荐的,它可能意味着代码结构设计存在问题。
💎 总结
简单来说,Spring的三级缓存是一个精巧的“缓兵之计”。它通过在Bean完全成型前就提供一个“预览版”(通过三级缓存工厂生成,可能是代理对象),让依赖它的其他Bean能继续组装下去,最终等所有Bean都组装完成后,再用“正式版”替换。
希望以上解释能帮助你理解Spring的三级缓存原理。
🔟 参考 10
Spring 的三级缓存机制是其解决单例 Bean 循环依赖问题的核心设计,尤其在处理 AOP 代理场景时至关重要。以下从原理、实现和设计意图三个维度详细解析:
一、三级缓存的结构与作用
Spring 的三级缓存定义在 DefaultSingletonBeanRegistry
类中,具体层级及功能如下:
缓存层级 | 名称 | 存储内容 | 核心作用 |
---|---|---|---|
一级缓存 | singletonObjects | 完全初始化的单例 Bean(包括依赖注入和 AOP 代理完成后的最终实例) | 直接提供可用的最终 Bean,供外部获取 |
二级缓存 | earlySingletonObjects | 实例化但未完成初始化的 Bean(如构造函数执行完成,但属性注入或初始化方法未执行) | 允许其他 Bean 在循环依赖中获取早期引用,打破循环等待 |
三级缓存 | singletonFactories | 存储生成早期引用的 ObjectFactory 对象 | 支持动态生成代理对象(如 AOP 场景),确保不同依赖链获取的代理对象引用一致 |
二、三级缓存解决循环依赖的流程(以 A → B → A 为例)
-
创建 Bean A
- 实例化 A:调用构造函数生成原始对象。
- 暴露早期引用:将
ObjectFactory
存入三级缓存(singletonFactories
),用于后续生成早期引用(可能是代理对象)。 - 依赖注入 B:发现 A 依赖 B,触发 B 的创建流程。
-
创建 Bean B
- 实例化 B:生成原始对象。
- 暴露早期引用:将 B 的
ObjectFactory
存入三级缓存。 - 依赖注入 A:发现 B 依赖 A,尝试从缓存获取 A 的实例。
-
解决循环依赖
- 从三级缓存获取 A 的工厂:调用
getObject()
生成 A 的早期引用(可能为代理对象)。 - 存入二级缓存:将 A 的早期引用移至
earlySingletonObjects
,供 B 注入。 - 完成 B 的初始化:注入 A 的早期引用后,B 完成初始化并存入一级缓存。
- 从三级缓存获取 A 的工厂:调用
-
完成 A 的初始化
- 注入 B 的最终实例:从一级缓存获取已完成的 B,完成 A 的依赖注入。
- A 存入一级缓存:A 的初始化完成后,移出二级缓存,最终存入一级缓存。
三、三级缓存设计的核心意图
-
解决循环依赖
- 通过提前暴露未完全初始化的 Bean(二级缓存),允许依赖链中的其他 Bean 获取引用,避免死锁。
-
支持 AOP 代理
- 三级缓存存储
ObjectFactory
,在生成早期引用时调用getEarlyBeanReference()
,确保代理对象的一致性。例如,若 A 被代理,B 注入的始终是同一代理实例。
- 三级缓存存储
-
并发控制与性能优化
- 双重检查锁:在
getSingleton()
方法中,首次创建 Bean 时加锁,后续直接读取缓存,减少锁竞争。 - 延迟初始化:三级缓存通过工厂模式延迟生成早期引用,避免不必要的对象创建。
- 双重检查锁:在
四、关键代码逻辑(简化版)
// AbstractAutowireCapableBeanFactory#doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化 BeanObject bean = createBeanInstance(beanName, mbd, args);// 2. 提前暴露工厂到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 3. 填充属性(依赖注入)populateBean(beanName, mbd, bean);// 4. 初始化 Bean(完成 AOP 代理等)initializeBean(beanName, bean, mbd);// 5. 移除三级缓存,存入一级缓存addSingleton(beanName, bean);return bean;
}// 获取早期引用的工厂方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {// 若存在 AOP 代理,返回代理对象return (mbd == null || !mbd.isSynthetic()) ? bean : wrapIfNecessary(beanName, bean, mbd);
}
五、常见问题与误区
-
为什么需要三级而非两级缓存?
二级缓存仅能存储原始对象,无法处理 AOP 代理场景。三级缓存通过工厂模式动态生成代理,确保引用一致性。 -
循环依赖是否设计缺陷?
Spring 官方认为循环依赖是设计问题,但实际开发中难以完全避免(如复杂业务场景)。三级缓存是权衡后的解决方案。 -
并发下的线程安全
通过ConcurrentHashMap
和双重检查锁(synchronized
+volatile
)保证多线程环境下缓存的正确性。
总结
Spring 的三级缓存通过分层存储 Bean 的不同生命周期状态,巧妙解决了循环依赖和 AOP 代理的兼容性问题。其设计体现了对性能、灵活性和线程安全的综合考量,是 Spring IoC 容器的核心机制之一。
🤔 参考 11
我们来详细、系统地解析一下 Spring 框架中三级缓存(3-level Cache) 的原理。这是一个理解 Spring 如何解决循环依赖(Circular Dependency) 问题的核心概念。
一句话概括
Spring 的三级缓存是为了解决单例(Singleton)Bean 的循环依赖问题,同时保证在处理循环依赖时,注入的代理对象(如 AOP 创建的代理)是同一个对象而设计的一套机制。
1. 什么是循环依赖?
循环依赖是指两个或以上的 Bean 相互持有对方,构成了一个循环引用链。例如:
- Bean A 的构造函数需要 Bean B 作为参数。
- Bean B 的构造函数需要 Bean A 作为参数。
Spring 默认支持基于 Setter 注入或字段注入的循环依赖,但不支持基于构造器注入的循环依赖。三级缓存主要解决的是前两种情况。
2. 三级缓存分别是什么?
在 Spring 的 DefaultSingletonBeanRegistry
类中,定义了三个非常重要的 Map,也就是我们常说的“三级缓存”:
-
一级缓存:
singletonObjects
- 类型:
ConcurrentHashMap<String, Object>
- 存放内容: 存放已经完全初始化好的、成熟的单例 Bean。
- 作用: 这是最主要的缓存。我们通过
ApplicationContext.getBean()
方法最终获取到的就是这里的 Bean。
- 类型:
-
二级缓存:
earlySingletonObjects
- 类型:
HashMap<String, Object>
- 存放内容: 存放早期的、未完全初始化的 Bean 实例(已经实例化,但属性还未填充)。
- 作用: 它是一级缓存的临时替补。当一个早期对象被其他 Bean 依赖过后,就会被放在这里,避免再次创建代理对象的开销。
- 类型:
-
三级缓存:
singletonFactories
- 类型:
HashMap<String, ObjectFactory<?>>
- 存放内容: 存放的是Bean 工厂对象(ObjectFactory),而不是 Bean 实例本身。这个工厂可以返回一个目标 Bean 的早期引用(可能是原始对象,也可能是代理对象)。
- 作用: 这是解决循环依赖和 AOP 代理问题的关键。它通过一个工厂来延迟决定最终返回的对象,从而能够智能地处理是否需要提前创建 AOP 代理。
- 类型:
3. 解决循环依赖的完整流程(核心)
让我们以两个 Bean:A 和 B 相互依赖为例(A 中有 B,B 中有 A)。
-
开始创建 A
- Spring 调用 A 的构造器,实例化一个“原始对象”。
- 随后,Spring 将创建 A 的
ObjectFactory
工厂对象,并放入三级缓存 (singletonFactories
) 中。
-
为 A 填充属性(Populate)
- Spring 发现 A 依赖 B,于是尝试去获取 Bean B。
-
开始创建 B
- Spring 调用 B 的构造器,实例化一个“原始对象”。
- 随后,Spring 将创建 B 的
ObjectFactory
工厂对象,并放入三级缓存 (singletonFactories
) 中。
-
为 B 填充属性(Populate)
- Spring 发现 B 依赖 A,于是尝试去获取 Bean A。
-
获取 A(关键步骤!)
- Spring 首先去一级缓存 (
singletonObjects
) 找 A,没有找到(A 还没创建完)。 - 然后去二级缓存 (
earlySingletonObjects
) 找 A,也没有找到(A 还没被依赖过)。 - 最后去三级缓存 (
singletonFactories
) 找,成功找到了 A 的ObjectFactory
。 - 调用
ObjectFactory.getObject()
方法。- 如果 A 是一个普通 Bean,这个方法直接返回 A 的原始对象。
- 如果 A 需要被 AOP 代理,这个方法会提前触发 AOP 逻辑,生成一个代理对象并返回。
- 将这个从三级缓存中得到的对象(可能是原始对象,也可能是代理对象)放入二级缓存 (
earlySingletonObjects
) 中,同时从三级缓存中移除对应的ObjectFactory
。 - 最后,将这个早期引用注入给 Bean B。
- Spring 首先去一级缓存 (
-
完成 B 的创建
- B 注入 A 成功后,继续完成 B 的其他生命周期步骤(初始化等)。
- B 创建完毕,被放入一级缓存 (
singletonObjects
),并从二、三级缓存中清除。
-
回到 A 的创建
- 此时 Bean B 已经创建好,成功注入到 A 中。
- A 继续完成它的属性填充和初始化步骤。
- A 创建完毕,被放入一级缓存 (
singletonObjects
),并从二、三级缓存中清除。
至此,循环依赖成功解决,A 和 B 都完成了创建。
4. 为什么需要三级缓存?两级不行吗?
这是一个非常经典的面试题。答案是:为了处理 AOP 代理,两级缓存理论上可以,但会有重复创建代理的风险,性能更差,而三级缓存的设计非常精妙地避免了这一点。
-
如果没有三级缓存(
singletonFactories
),只有一级和二级缓存:- 在上述第 5 步,我们无法通过一个工厂来“智能地”判断是否需要创建代理。
- 我们只能选择:要么在实例化后立刻进行 AOP 代理,然后把这个代理对象直接放入二级缓存。
- 问题: 如果这个 Bean 没有被循环依赖(即没有其他 Bean 提前引用它),那么它根本不需要提前生成代理。提前创建代理是不合理且浪费的,因为代理的最终生成可能还依赖于后续的初始化操作(如
@PostConstruct
)。 - 更大的问题: 如果多个 Bean 同时循环依赖它,这个提前创建的代理对象可能会被多次生成(因为每次依赖都要走一遍创建逻辑),违背了单例原则。
-
三级缓存的作用:
- 它通过一个
ObjectFactory
来延迟决策。只有在真正发生循环依赖,需要提前暴露引用时,才会调用工厂的getObject()
方法。 - 这个方法内部有逻辑保证:对于同一个 Bean,多次调用
getObject()
返回的都是同一个代理对象,确保了单例。 - 如果没有发生循环依赖,这个工厂永远不会被调用,Bean 会按正常流程在初始化之后才创建代理,这样更加合理和高效。
- 它通过一个
简单比喻:
- 二级缓存方案: 不管有没有客人来,先把菜做好放在备餐台(二级缓存)上。
- 三级缓存方案: 先把食材准备好,并雇好一个厨师(
ObjectFactory
)。只有客人点这道菜时,厨师才立刻现场制作,并且保证所有客人吃到的都是同一份。
总结
缓存级别 | 名称(Map) | 内容 | 目的 |
---|---|---|---|
一级缓存 | singletonObjects | 完整的单例 Bean | 提供最终可用的 Bean |
二级缓存 | earlySingletonObjects | 早期的 Bean 引用(可能是代理) | 避免重复创建早期引用,提升性能 |
三级缓存 | singletonFactories | 生成早期引用的工厂 | 核心: 延迟化、智能化处理 AOP 代理,保证单例 |
核心思想: Spring 通过提前暴露对象实例(存入三级缓存)来解决循环依赖,并通过 ObjectFactory
的巧妙设计来统一处理普通 Bean 和代理 Bean 的创建过程,既解决了问题,又保证了性能和高扩展性。
🤔 参考 12
Spring 的三级缓存机制是其解决 bean 循环依赖问题的关键设计,以下是对其原理及相关内容的详细介绍:
一、三级缓存的结构与作用
-
一级缓存
singletonObjects
- 功能: 存储已完全初始化并可用的单例 Bean 实例[1][2][4]。
- 特点: 其中的 Bean 已完成所有属性注入和非惰性初始化操作,可直接返回给请求者使用[1][2][4]。
-
二级缓存
earlySingletonObjects
- 功能: 存放早期暴露的 Bean 引用,这些对象已完成实例化但尚未完成属性注入或初始化[1][2][4]。
- 作用: 允许其他 Bean 在创建过程中引用尚未完全初始化的 Bean,从而解决循环依赖问题[1][2][4]。
-
三级缓存
singletonFactories
- 功能: 存储可生成 Bean 实例的工厂对象(
ObjectFactory
),而非直接存储 Bean 实例[1][2][4]。 - 核心作用: 应对 AOP 代理场景。若 Bean 需要被代理(如通过
SmartInstantiationAwareBeanPostProcessor
),则通过工厂动态生成代理对象而非原始对象[1][5]。
- 功能: 存储可生成 Bean 实例的工厂对象(
二、三级缓存解决循环依赖的流程
-
首次创建 Bean A
- Spring 实例化 Bean A 后,将其封装为
ObjectFactory
并存入三级缓存singletonFactories
[1][5]。此时暂不放入一/二级缓存。
- Spring 实例化 Bean A 后,将其封装为
-
处理 Bean A 的依赖 Bean B
- 当尝试注入 Bean B 时,发现其尚未创建,于是开始创建 Bean B。同样地将Bean B的
ObjectFactory
存入三级缓存。
- 当尝试注入 Bean B 时,发现其尚未创建,于是开始创建 Bean B。同样地将Bean B的
-
检测到循环依赖
- 当创建 Bean B 的过程中试图注入 Bean A 时,从三级缓存中获取 Bean A 的
ObjectFactory
,调用其getObject()
方法生成早期引用[1][5]。
- 当创建 Bean B 的过程中试图注入 Bean A 时,从三级缓存中获取 Bean A 的
-
升级缓存层级
- 将 Bean A 的早期引用从三级缓存移至二级缓存
earlySingletonObjects
,供 Bean B 完成属性注入[1][5]。
- 将 Bean A 的早期引用从三级缓存移至二级缓存
-
完成初始化并最终放入一级缓存
- Bean B 完成属性注入后,将其完整实例放入一级缓存
singletonObjects
[1][5]。 - 随后继续完成 Bean A 的初始化,最终也将 Bean A 放入一级缓存。
- Bean B 完成属性注入后,将其完整实例放入一级缓存
三、为何需要三级缓存而非二级?
-
支持 AOP 代理:若仅用二级缓存(直接存储未初始化完成的 Bean),则无法区分是否需要代理。三级缓存通过
ObjectFactory
可在获取 Bean 时动态判断是否需要生成代理对象[1][5]。 -
延迟代理对象的创建:避免了在 Bean 生命周期早期错误地生成代理对象,确保 AOP 逻辑仅在必要时执行[1][5]。
-
线程安全与性能优化:三级缓存通过分层设计和同步块控制,减少了并发场景下的锁竞争,提升了性能[5]。
四、关键前提条件
-
单例模式:循环依赖的两个 Bean 必须都是单例的[3][4]。
-
非构造函数注入:构造函数注入会导致实例化阶段陷入死循环,因为构造函数要求所有依赖立即可用[3][4]。
总的来说,Spring 的三级缓存通过分阶段存储 Bean 的不同状态(实例化 → 属性注入 → 初始化完成),结合工厂模式动态生成代理对象,巧妙解决了循环依赖问题。这一机制不仅保证了Bean生命周期的正确性,还兼容了 AOP 等高级特性,是 Spring IoC 容器的核心设计之一。
🤔 参考 13
Spring 的三级缓存机制是 Spring 解决循环依赖问题的核心机制,主要应用于单例 Bean 的创建过程中。它由三个缓存(Map)组成,分别用于存储不同状态的 Bean 对象。以下是三级缓存的原理和作用:
1. 三级缓存的组成
Spring 使用三个 Map 结构作为缓存,分别如下:
-
一级缓存(singletonObjects)
存放已经完全初始化好的单例 Bean(可以直接使用的 Bean)。 -
二级缓存(earlySingletonObjects)
存放提前暴露的“早期 Bean”(尚未完成属性注入和初始化)。 -
三级缓存(singletonFactories)
存放 Bean 工厂对象(ObjectFactory),用于创建早期 Bean 的代理对象(用于支持 AOP)。
2. 三级缓存的工作流程
当 Spring 创建一个单例 Bean 时,会经历以下流程:
-
创建 Bean 实例(newInstance)
- 调用构造方法创建一个原始对象(未注入属性、未初始化)。
-
将 Bean 工厂放入三级缓存中
- 将一个
ObjectFactory
放入三级缓存singletonFactories
,用于后续获取代理对象。
- 将一个
-
填充属性(populateBean)
- 如果依赖的其他 Bean 还未创建,会触发它们的创建流程,可能形成循环依赖。
-
提前暴露 Bean(放入二级缓存)
- 从三级缓存中获取 Bean 工厂,创建代理对象(如果有 AOP 需要),并将其移动到二级缓存。
-
完成初始化(initializeBean)
- 注入属性、调用初始化方法(如 init-method、@PostConstruct)。
-
将 Bean 放入一级缓存
- 完全初始化好的 Bean 被放入一级缓存
singletonObjects
,供其他 Bean 使用。
- 完全初始化好的 Bean 被放入一级缓存
3. 如何解决循环依赖?
以 A 依赖 B,B 又依赖 A 的情况为例:
- 创建 A 时,A 被实例化后放入三级缓存。
- A 填充属性时发现依赖 B,于是开始创建 B。
- B 实例化后,填充属性时发现依赖 A,于是从 A 的三级缓存中获取早期的 A(可能是代理对象)。
- B 创建完成后放入一级缓存,A 继续完成初始化。
- 最终 A 和 B 都被正确创建,解决循环依赖。
4. 注意事项
- 只适用于单例作用域的 Bean。
- 不能解决构造器注入的循环依赖(因为构造器注入必须在实例化时完成依赖注入)。
- 依赖的提前暴露是关键,三级缓存机制确保了即使对象未完全初始化,也能被其他对象引用。
总结
Spring 的三级缓存机制通过提前暴露未完全初始化的 Bean,结合工厂模式和代理机制,巧妙地解决了单例 Bean 的循环依赖问题,是 Spring 容器设计中的经典实现。
🤔 参考 14
Spring的三级缓存是Spring框架在管理Bean生命周期时采用的一种核心机制,主要用于解决循环依赖问题,同时优化Bean的创建效率。其原理通过三个不同层级的缓存(一级、二级、三级)存储Bean在不同生命周期阶段的状态,确保单例Bean的线程安全创建和高效复用。
一、三级缓存的组成与作用
-
一级缓存(SingletonObjects)
- 存储内容:完全初始化好的单例Bean。
- 作用:Bean在完成所有初始化步骤(如依赖注入、初始化方法调用、AOP代理等)后,会被放入一级缓存。后续获取Bean时直接从此缓存返回,避免重复创建。
- 特点:线程安全,使用
ConcurrentHashMap
实现,保证高并发下的正确性。
-
二级缓存(EarlySingletonObjects)
- 存储内容:已实例化但未完全初始化的Bean(半成品Bean)。
- 作用:在Bean初始化过程中,若其他Bean依赖它,Spring会先将半成品Bean放入二级缓存,供依赖方提前使用。
- 特点:解决循环依赖的关键,允许Bean在未完全初始化时被引用,但避免重复创建。
-
三级缓存(SingletonFactories)
- 存储内容:Bean的
ObjectFactory
对象(通常是一个Lambda表达式)。 - 作用:当Bean需要被代理(如AOP场景)时,三级缓存存储的是生成代理对象的工厂。通过工厂可以动态决定返回原始Bean还是代理Bean,保证全局唯一性。
- 特点:解决AOP代理与循环依赖的兼容问题,确保代理对象在循环依赖中也能正确生成。
- 存储内容:Bean的
二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:
-
创建Bean A
- Spring先检查一级缓存,未找到Bean A。
- 创建Bean A的实例(未注入依赖),将其对应的
ObjectFactory
放入三级缓存。 - 开始填充Bean A的属性,发现依赖Bean B。
-
创建Bean B
- 检查一级缓存,未找到Bean B。
- 创建Bean B的实例,将其
ObjectFactory
放入三级缓存。 - 开始填充Bean B的属性,发现依赖Bean A。
-
解决Bean A的循环依赖
- Spring从三级缓存获取Bean A的
ObjectFactory
,调用getObject()
方法生成Bean A的早期引用(可能是代理对象)。 - 将Bean A的早期引用从三级缓存移除,并放入二级缓存。
- Bean B完成属性注入(使用二级缓存中的Bean A早期引用),继续初始化。
- Spring从三级缓存获取Bean A的
-
完成Bean B的初始化
- Bean B完成所有初始化步骤后,被放入一级缓存。
- 从二级缓存中移除Bean A的早期引用(若存在)。
-
完成Bean A的初始化
- Spring继续初始化Bean A,使用一级缓存中的Bean B完成属性注入。
- Bean A完成所有初始化步骤后,被放入一级缓存。
三、三级缓存的核心优势
-
解决循环依赖
通过提前暴露半成品Bean(二级缓存)和动态生成代理对象(三级缓存),避免循环依赖导致的无限递归或死锁。 -
优化性能
- 减少重复创建:已初始化的Bean直接从一级缓存返回,避免重复实例化。
- 懒加载支持:二级缓存实现Bean的按需初始化,降低启动时间。
-
兼容AOP代理
三级缓存的ObjectFactory
机制确保代理对象在循环依赖中也能正确生成,解决原始Bean与代理Bean的冲突问题。 -
线程安全保障
一级缓存使用ConcurrentHashMap
,二级和三级缓存通过同步块(synchronized
)保证多线程环境下的正确性。
四、三级缓存的适用场景
- 单例Bean的循环依赖:仅对作用域为
singleton
的Bean有效,原型(prototype
)Bean无法使用三级缓存。 - AOP代理场景:当Bean需要被代理时,三级缓存的工厂机制确保代理对象在循环依赖中也能正确生成。
- 高并发环境:通过缓存机制减少锁竞争,提升Bean创建效率。
五、源码解析关键方法
-
getSingleton(String beanName, boolean allowEarlyReference)
- 核心逻辑:按一级→二级→三级缓存的顺序查找Bean。
- 若在三级缓存找到,调用
ObjectFactory.getObject()
生成早期引用,移入二级缓存并删除三级缓存条目。
-
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
- 将Bean的
ObjectFactory
放入三级缓存,用于后续循环依赖的解决。
- 将Bean的
-
doGetBean()
与createBean()
- 控制Bean的创建流程,包括依赖注入、初始化、缓存操作等。
🤔 参考 15
Spring的三级缓存机制是其解决循环依赖问题的核心设计,主要应用于单例(Singleton)Bean的创建过程中。这个机制通过三个Map(通常称为“三级缓存”)来实现,确保在复杂的依赖注入场景下,Bean能够被正确、高效地创建和初始化。
以下是三级缓存的具体原理和作用:
1. 三级缓存的定义
Spring的DefaultSingletonBeanRegistry
类中定义了三个Map,它们共同构成了三级缓存:
-
一级缓存 (
singletonObjects
):- 类型:
ConcurrentHashMap<String, Object>
- 作用: 存放完全初始化好的单例Bean实例。这些Bean已经完成了实例化、属性填充(依赖注入)和初始化方法(如
@PostConstruct
、InitializingBean
)的调用。 - 特点: 这是最终的、可供使用的Bean仓库。当一个Bean被请求时,Spring会首先从此缓存中查找。
- 类型:
-
二级缓存 (
earlySingletonObjects
):- 类型:
ConcurrentHashMap<String, Object>
- 作用: 存放提前暴露的、原始的Bean实例。这些实例已经通过构造函数创建(实例化完成),但尚未进行属性填充和初始化。
- 特点: 用于解决循环依赖。当一个Bean A在创建过程中依赖Bean B,而Bean B又依赖Bean A时,Spring会将Bean A的早期引用(一个未完全初始化的对象)放入此缓存,供Bean B注入使用。
- 类型:
-
三级缓存 (
singletonFactories
):- 类型:
ConcurrentHashMap<String, ObjectFactory<?>>
- 作用: 存放能够创建早期Bean实例的工厂(
ObjectFactory
)。这个工厂通常是一个Lambda表达式,其核心是getEarlyBeanReference()
方法。 - 特点: 这是解决循环依赖和AOP代理的关键。它不直接存放对象,而是存放一个可以获取对象的“生产指令”。当需要早期引用时,会通过这个工厂来获取。
- 类型:
2. 三级缓存的工作流程(以解决循环依赖为例)
假设存在循环依赖:AService
依赖 BService
,而 BService
又依赖 AService
。
-
开始创建
AService
:- Spring发现需要创建
AService
,首先检查一级缓存singletonObjects
,没有找到。 - 然后检查二级缓存
earlySingletonObjects
,也没有找到。 - 接着检查三级缓存
singletonFactories
,同样没有。 - 于是开始创建
AService
。
- Spring发现需要创建
-
暴露
AService
的早期引用:AService
通过构造函数实例化完成(此时AService
对象已存在,但属性还未注入)。- Spring将一个
ObjectFactory
(工厂)放入三级缓存singletonFactories
中。这个工厂的作用是:当被调用时,可以返回AService
的早期引用。 - 关键点: 此时
AService
的早期引用尚未真正创建,只是准备好了创建它的“方法”。
-
注入依赖 - 创建
BService
:AService
需要注入BService
,于是Spring开始创建BService
。BService
的创建流程类似,实例化完成后,也会将其ObjectFactory
放入三级缓存。BService
需要注入AService
。
-
解决循环依赖 - 获取
AService
的早期引用:- 在为
BService
注入AService
时,Spring再次查找AService
。 - 一级、二级缓存都没有,但在三级缓存中找到了
AService
的ObjectFactory
。 - Spring调用这个
ObjectFactory
的getObject()
方法。 getObject()
方法内部会调用getEarlyBeanReference()
。这一步至关重要:- 如果
AService
需要被AOP代理(例如有@Transactional
注解),那么getEarlyBeanReference()
会在这里创建代理对象。 - 如果不需要代理,则直接返回原始的
AService
实例。
- 如果
- 将得到的早期引用(可能是原始对象,也可能是代理对象)放入二级缓存
earlySingletonObjects
。 - 同时,从三级缓存中移除
AService
的ObjectFactory
。这保证了早期引用只会被创建一次。 - 将这个早期引用注入到
BService
中。
- 在为
-
完成
BService
的创建:BService
完成属性填充和初始化,成为一个完整的Bean,放入一级缓存singletonObjects
。- 从二级和三级缓存中移除
BService
的相关条目。
-
完成
AService
的创建:- 回到
AService
的创建流程,此时BService
已经创建完毕。 - 将
BService
注入到AService
中。 AService
完成初始化,成为一个完整的Bean,放入一级缓存singletonObjects
。- 从二级和三级缓存中移除
AService
的相关条目。
- 回到
3. 为什么需要三级缓存?二级不够吗?
这是理解Spring设计精髓的关键。
-
如果只有二级缓存:在
AService
实例化后,直接将其原始对象放入二级缓存。当BService
需要AService
时,从二级缓存获取并注入。 -
问题在于AOP:如果
AService
是一个需要被代理的Bean(比如有@Transactional
),那么最终放入一级缓存的应该是代理对象,而不是原始对象。但如果在早期就将原始对象暴露出去并被其他Bean持有,那么当AService
最终创建完成时,生成的代理对象与之前注入的原始对象就不一致了,导致出现两个不同的实例,破坏了单例原则和AOP的预期行为。 -
三级缓存的解决方案:
- 三级缓存不直接存放对象,而是存放一个工厂。
- 这个工厂(
ObjectFactory
)的getObject()
方法会在被调用时,通过getEarlyBeanReference()
动态决定返回的是原始对象还是代理对象。 - 这样,无论是早期引用还是最终的完整Bean,都保证是同一个对象(要么都是原始对象,要么都是代理对象),从而保证了对象的一致性。
总结
Spring的三级缓存是一个精巧的设计:
- 一级缓存:存放最终的、完整的单例Bean。
- 二级缓存:存放提前暴露的原始Bean实例(或代理),用于打破循环依赖。
- 三级缓存:存放创建早期引用的工厂,核心作用是解决循环依赖与AOP代理之间的矛盾,确保无论何时获取的引用,最终指向的都是同一个最终对象(特别是代理对象)。
通过这三级缓存的协同工作,Spring能够在保证Bean生命周期完整性的前提下,高效地解决单例Bean之间的循环依赖问题。
🤔 参考 16 Spring 如何解决循环依赖
Spring 如何解决循环依赖
1. 循环依赖的定义与类型
1.1 什么是循环依赖
// 示例:两个 Bean 相互依赖
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowired private UserService userService; // 循环依赖
}
1.2 循环依赖的类型
- 构造器循环依赖:无法解决
- Setter/字段循环依赖:可以通过三级缓存解决
- 原型 Bean 循环依赖:无法解决
2. 三级缓存机制
2.1 三级缓存定义
在 DefaultSingletonBeanRegistry
中:
public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}
2.2 三级缓存的作用
缓存级别 | 存储内容 | 作用 |
---|---|---|
一级缓存 | 完全初始化好的 Bean | 提供最终的单例实例 |
二级缓存 | 早期暴露的对象 | 避免重复创建代理对象 |
三级缓存 | ObjectFactory 工厂 | 支持 AOP 代理等后处理 |
3. 循环依赖解决流程
3.1 核心解决算法
// 获取 Bean 的核心方法
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. 从三级缓存获取 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过工厂创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,从三级缓存移除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
3.2 详细解决步骤
以 UserService
和 OrderService
循环依赖为例:
// 步骤1:开始创建 UserService
1. beforeSingletonCreation("userService") // 标记正在创建
2. instance = instantiateBean("userService") // 实例化 UserService
3. addSingletonFactory("userService", () -> getEarlyBeanReference("userService", mbd, instance)) // 添加到三级缓存// 步骤2:填充 UserService 属性
4. populateBean("userService", mbd, instance) // 发现需要 orderService
5. getBean("orderService") // 开始创建 OrderService// 步骤3:开始创建 OrderService
6. beforeSingletonCreation("orderService") // 标记正在创建
7. instance = instantiateBean("orderService") // 实例化 OrderService
8. addSingletonFactory("orderService", () -> getEarlyBeanReference("orderService", mbd, instance)) // 添加到三级缓存// 步骤4:填充 OrderService 属性
9. populateBean("orderService", mbd, instance) // 发现需要 userService
10. getSingleton("userService") // 获取 UserService- 一级缓存:无- 二级缓存:无- 三级缓存:找到 UserService 的 ObjectFactory- 调用 factory.getObject() 获取早期引用- 将 UserService 移到二级缓存// 步骤5:完成 OrderService 创建
11. initializeBean("orderService") // 初始化 OrderService
12. addSingleton("orderService", instance) // 放入一级缓存// 步骤6:完成 UserService 创建
13. 回到 UserService 的属性填充,注入 OrderService
14. initializeBean("userService") // 初始化 UserService
15. addSingleton("userService", instance) // 放入一级缓存
4. Bean 创建的关键时机点
4.1 Bean 生命周期与缓存
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(创建原始对象)Object beanInstance = instantiateBean(beanName, mbd);// 2. 暴露早期引用(关键步骤!)boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {// 添加到三级缓存 - 解决循环依赖的核心addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性填充(可能触发循环依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}
4.2 三级缓存的添加
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 添加到三级缓存this.singletonFactories.put(beanName, singletonFactory);// 清理二级缓存this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
}
5. AOP 代理的特殊处理
5.1 代理对象的创建时机
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会创建并返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}
5.2 AOP 代理示例
@Service
public class UserService {@Autowiredprivate OrderService orderService;@Transactional // 需要 AOP 代理public void updateUser() {// 事务方法}
}@Service
public class OrderService {@Autowiredprivate UserService userService; // 这里注入的应该是代理对象
}
处理流程:
UserService
实例化后,三级缓存中的ObjectFactory
会检查是否需要 AOP 代理- 由于有
@Transactional
,getEarlyBeanReference
返回代理对象 OrderService
注入的是UserService
的代理对象- 保证事务功能正常工作
6. 无法解决的循环依赖情况
6.1 构造器循环依赖
@Service
public class UserService {private final OrderService orderService;// 构造器注入 - 无法解决!public UserService(OrderService orderService) {this.orderService = orderService;}
}@Service
public class OrderService {private final UserService userService;public OrderService(UserService userService) {this.userService = userService;}
}
原因:Bean 还没有实例化,无法添加到三级缓存,Spring 会直接抛出 BeanCurrentlyInCreationException
6.2 原型 Bean 循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class OrderService {@Autowiredprivate UserService userService;
}
原因:原型 Bean 每次都会创建新实例,Spring 不支持原型 Bean 的循环依赖
7. 解决方案与最佳实践
7.1 使用 @Lazy 注解
@Service
public class UserService {@Lazy // 延迟注入,打破循环依赖@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowiredprivate UserService userService; // 正常注入
}
7.2 使用 Setter 注入
@Service
public class UserService {private OrderService orderService;// Setter 注入@Autowiredpublic void setOrderService(OrderService orderService) {this.orderService = orderService;}
}
7.3 使用 ApplicationContext
@Service
public class UserService implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}public void someMethod() {// 需要时再获取 OrderServiceOrderService orderService = applicationContext.getBean(OrderService.class);}
}
7.4 代码重构
// 方案1:提取公共逻辑到第三个类
@Service
public class CommonService {// 公共逻辑
}@Service
public class UserService {@Autowiredprivate CommonService commonService;
}@Service
public class OrderService {@Autowiredprivate CommonService commonService;
}// 方案2:使用接口分离
public interface UserOperation {void userOperation();
}public interface OrderOperation {void orderOperation();
}@Service
public class UserService implements UserOperation {@Autowiredprivate OrderOperation orderOperation;
}@Service
public class OrderService implements OrderOperation {@Autowiredprivate UserOperation userOperation;
}
8. 调试与问题排查
8.1 启用循环依赖日志
########## application.properties
logging.level.org.springframework.beans=DEBUG
logging.level.org.springframework.context=DEBUG
8.2 自定义循环依赖检测
@Component
public class CircularDependencyChecker implements ApplicationRunner {@Autowiredprivate ConfigurableListableBeanFactory beanFactory;@Overridepublic void run(ApplicationArguments args) {detectCircularDependencies();}private void detectCircularDependencies() {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {try {// 尝试创建 Bean,触发循环依赖检测Object bean = beanFactory.getBean(beanName);System.out.println("成功创建: " + beanName);} catch (BeanCurrentlyInCreationException e) {System.err.println("循环依赖 detected: " + e.getMessage());}}}
}
8.3 查看缓存状态
@Component
public class CacheStatusLogger implements ApplicationRunner {@Autowiredprivate AbstractApplicationContext context;@Overridepublic void run(ApplicationArguments args) throws Exception {DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) context.getBeanFactory();// 通过反射查看缓存状态printCacheStatus(registry, "singletonObjects");printCacheStatus(registry, "earlySingletonObjects");printCacheStatus(registry, "singletonFactories");}private void printCacheStatus(DefaultSingletonBeanRegistry registry, String cacheName) {try {Field field = DefaultSingletonBeanRegistry.class.getDeclaredField(cacheName);field.setAccessible(true);Map<?, ?> cache = (Map<?, ?>) field.get(registry);System.out.println(cacheName + " size: " + cache.size());System.out.println(cacheName + " keys: " + cache.keySet());} catch (Exception e) {e.printStackTrace();}}
}
9. Spring Boot 配置选项
9.1 相关配置属性
########## application.properties########## 是否允许循环引用(默认 true)
spring.main.allow-circular-references=true########## 是否允许 Bean 定义覆盖(默认 false)
spring.main.allow-bean-definition-overriding=false########## 懒初始化(可以帮助避免某些循环依赖)
spring.main.lazy-initialization=false
9.2 禁用循环依赖支持
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication application = new SpringApplication(Application.class);// 禁用循环引用application.setAllowCircularReferences(false);application.run(args);}
}
10. 总结
Spring 通过三级缓存机制解决循环依赖的核心要点:
解决的条件:
- ✅ 单例 Bean
- ✅ Setter/字段注入
- ✅ 非构造器注入
无法解决的情况:
- ❌ 构造器循环依赖
- ❌ 原型 Bean 循环依赖
- ❌ @Async 等方法级别的代理
核心原理:
- 提前暴露:Bean 实例化后立即暴露到三级缓存
- 工厂模式:通过 ObjectFactory 延迟决定返回原始对象还是代理对象
- 缓存升级:从三级缓存 → 二级缓存 → 一级缓存
- AOP 支持:在早期引用阶段处理代理逻辑
最佳实践:
- 优先使用 Setter 注入而非构造器注入
- 使用
@Lazy
注解打破循环依赖 - 合理设计代码结构,避免循环依赖
- 在必要时进行代码重构
理解 Spring 的循环依赖解决机制对于设计复杂的 Spring 应用、排查启动问题以及进行性能优化都具有重要意义。