Spring三级缓存
大约 3 分钟
阅读提示
这页建议按“循环依赖是什么 -> 三级缓存是什么 -> 为什么必须三级”顺序复习。
面试时优先说主流程,再补 AOP 代理和边界条件,答案会更完整。
1、什么是循环依赖?
回答提示:
- A 依赖 B,B 又依赖 A。
- 在 Spring Bean 创建时会造成“对象还没创建完就被别人依赖”的问题。
参考回答:
- 循环依赖本质是依赖闭环,Spring 需要在初始化过程中打破这个闭环。
2、Bean 创建的三个阶段
- 实例化(new 出对象)。
- 属性填充(依赖注入)。
- 初始化(执行初始化逻辑、后置处理器)。
3、三级缓存分别存什么?
- 一级缓存
singletonObjects:完整初始化后的单例 Bean。 - 二级缓存
earlySingletonObjects:提前暴露的早期 Bean(半成品)。 - 三级缓存
singletonFactories:ObjectFactory,用于按需生成早期引用。
4、三级缓存如何解决循环依赖?
回答提示:
- A 实例化后先把工厂放入三级缓存。
- 创建 B 时发现依赖 A,从三级缓存拿到 A 的早期引用。
- B 完成初始化后回填给 A,最后 A 完成初始化。
参考回答:
- 关键点不是“提前暴露半成品”本身,而是通过工厂延迟决定返回什么引用。
5、为什么不能只用二级缓存?
回答提示:
- 二级缓存直接存对象,无法灵活决定“原始对象还是代理对象”。
- 三级缓存存工厂,可以在获取早期引用时判断是否需要 AOP 代理。
参考回答:
- 如果只有二级缓存,B 可能拿到 A 的原始对象,导致 AOP 逻辑失效。
- 三级缓存通过
ObjectFactory#getObject()解决了这个时机问题。
6、三级缓存和 AOP 的关系
- A 需要被代理时,早期引用应优先返回代理对象。
- 这样依赖 A 的其他 Bean 拿到的是最终可用形态。
- 避免“有的地方是原始对象、有的地方是代理对象”的不一致问题。
7、循环依赖的边界条件(常见追问)
- 三级缓存主要解决单例 Bean 的属性注入循环依赖。
- 构造器循环依赖通常无法通过三级缓存解决。
- 原型 Bean 不走单例缓存体系,也不适用这套机制。
8、面试表达模板
可直接复述:
- Spring 通过三级缓存解决的是“单例 Bean 属性注入场景”的循环依赖。
- 一级放成品、二级放早期对象、三级放工厂,核心价值是支持代理对象按需提前暴露。
- 这也是为什么三级缓存不是为了“多一层缓存”,而是为了“延迟决策对象形态”。
