Spring 面试题, 为什么 Spring 循环依赖需要三级缓存,二级不够吗?
Spring 面试题, 为什么 Spring 循环依赖需要三级缓存,二级不够吗?
QA
Step 1
Q:: 为什么 Spring 循环依赖需要三级缓存,二级缓存不够吗?
A:: Spring 循环依赖的解决方案依赖于三级缓存机制,目的是解决构造器注入和属性注入中的循环依赖问题。二级缓存存储的是半成品 bean(尚未完全初始化的 bean),而三级缓存存储的是可以通过代理对象提前暴露的 bean。如果只使用二级缓存,在某些情况下(如 AOP 代理)无法获取到早期引用的代理对象,这样会导致循环依赖问题无法解决。三级缓存则通过提前暴露代理对象来打破这种循环依赖,从而实现更复杂的依赖场景。
Step 2
Q:: 什么是 Spring 的三级缓存?
A:: Spring 的三级缓存是解决循环依赖的重要机制,分为三个层次:第一级缓存为单例池(singletonObjects),用于存储完全初始化完成的 bean;第二级缓存为早期单例池(earlySingletonObjects),用于存储部分初始化的 bean 实例;第三级缓存为单例工厂(singletonFactories),用于存储对象工厂,可以生成 bean 的代理对象或实例。当一个 bean 在初始化时,如果检测到循环依赖,Spring 会将这个 bean 放入第三级缓存,以供其他 bean 进行引用。
Step 3
Q:: 如何在 Spring 中解决构造器注入导致的循环依赖?
A:: Spring 无法通过缓存机制解决构造器注入的循环依赖,因为在构造器注入的过程中,bean 还未创建,无法进行缓存处理。解决构造器注入循环依赖的方式通常是重新设计 bean 的依赖关系,或者使用 setter 方法注入而非构造器注入。通过 setter 方法注入可以利用 Spring 的三级缓存机制来解决循环依赖。
Step 4
Q:: 在 Spring 中如何手动处理 bean 的循环依赖问题?
A:: 手动处理 Spring 中的循环依赖问题可以通过将构造器注入改为 setter 注入,或者使用 @Lazy
注解延迟加载 bean,来避免在构造器阶段立即初始化 bean 依赖,从而打破循环依赖。此外,也可以通过重构代码,降低 bean 之间的耦合,减少依赖关系,或者使用代理模式来缓解循环依赖问题。