Spring的三级缓存机制是为了解决单例Bean之间的循环依赖问题,尤其是在涉及AOP代理的情况下。以下是三级缓存的原理和作用:
1.一级缓存(singletonObjects):
存储完全初始化的Bean实例,这些对象已经完成所有属性注入和初始化方法调用,可以直接使用。在创建Bean时,Spring首先检查一级缓存中是否存在该Bean,如果存在则直接返回。
2.二级缓存(earlySingletonObjects):
存放早期暴露的Bean引用,这些对象尚未完成属性注入,但已经被其他Bean引用。二级缓存的作用是避免在多重循环依赖中重复创建动态代理对象。
3.三级缓存(singletonFactories):
保存ObjectFactory对象,通过getObject()方法获取Bean的早期引用(原始对象或代理对象)。三级缓存的核心作用是在需要时延迟生成正确的引用,尤其是在处理AOP代理时。当Bean被实例化后,其ObjectFactory会被注册到三级缓存中。在属性注入阶段,如果发现循环依赖,Spring会从三级缓存中获取ObjectFactory,并调用getObject()方法生成代理对象(如果需要AOP),然后将其存入二级缓存。
为什么需要三级缓存?
解决循环依赖:在循环依赖场景中,Bean可能需要提前暴露自己的引用,以便其他Bean能够完成注入。三级缓存通过ObjectFactory提供了一种延迟生成引用的机制,确保在需要时生成正确的对象。
处理AOP代理:如果只用二级缓存,可能会导致注入的对象形态错误,甚至破坏单例原则。三级缓存允许在循环依赖时特殊处理,生成代理对象并正确注入,同时保持Bean生命周期的完整性(正常情况下代理在初始化后生成)。
总结来说,三级缓存的设计既维持了Bean生命周期的正常流程,又在循环依赖时提供了必要的灵活性,确保代理对象的正确生成和注入。
注意:
从Spring Boot 2.6版本开始,默认禁止循环依赖。如果项目中存在循环依赖,应用将无法启动并抛出异常。
虽然默认禁用了循环依赖,但三级缓存机制仍然保持开启状态,只有在显式配置allow-circular-references=true后,三级缓存才会被用于解决循环依赖问题
对于非循环依赖的场景,三级缓存继续正常工作,管理Bean的生命周期