理解Spring的3级缓存与循环依赖机制

版权申诉
0 下载量 30 浏览量 更新于2024-08-07 收藏 2.07MB DOC 举报
"对Spring框架中的3级缓存和循环引用机制进行深入解析" 在Spring框架中,当我们在编写代码时经常使用`@Autowired`注解来自动装配其他对象。然而,有时会出现循环依赖的情况,令人意外的是,Spring并不会直接抛出错误。这是因为Spring具有一套复杂的管理机制来处理这种循环依赖,主要涉及其内部的3级缓存系统。 **一、循环依赖的理解** 1. **循环依赖的类型** 我们主要关注的是单例模式下的`@Autowired`循环依赖,不涉及构造器注入或原型作用域Bean的情况。例如,两个单例Bean A和B相互依赖,A中注入B,B中也注入A。 2. **代理对象的创建** 在正常情况下,AOP增强会在Bean完全初始化后,即`BeanPostProcessor#postProcessAfterInitialization`方法中进行。但如果存在循环依赖,Spring会在`getEarlyBeanReference`中提前创建代理对象,以便在初始化过程中解决依赖关系。 3. **3级缓存详解** - **一级缓存(singletonObjects)**: 存储完全初始化好的Bean,可供直接使用。 - **二级缓存(earlySingletonObjects)**: 保存了部分初始化的Bean,属性尚未设置,初始化未完成。 - **三级缓存(singletonFactories)**: 存储了Bean的工厂对象,用于根据需要创建Bean实例。 当Bean的实例化开始时,它首先被放入三级缓存,随着属性的设置,逐渐过渡到二级缓存,最终完全初始化后进入一级缓存。 **二、从3级缓存获取对象的过程** 在`DefaultSingletonBeanRegistry`中,通过`getSingleton(String beanName, boolean allowEarlyReference)`方法从缓存中获取Bean。这个方法首先检查一级缓存,如果找不到,再尝试从二级缓存获取,最后如果依然找不到,会从三级缓存的ObjectFactory中通过`getObject()`方法创建一个新的实例。 **三、Spring Bean的创建流程** 1. **实例化Bean**: 使用`instanceWrapper.getWrappedInstance();`创建一个新的Bean实例,如`new Bean()`。 2. **加入三级缓存**: `addSingletonFactory(beanName,()->getEarlyBeanReference(beanName,mbd,bean));`将新实例加入到三级缓存,此时Bean可能还未完全初始化。 3. **设置Bean属性**: `populateBean(beanName, mbd, instanceWrapper);`填充Bean的属性,完成依赖注入。 4. **初始化Bean**: 如果Bean需要后处理器处理(如AOP),则在`BeanPostProcessor`中进行。 5. **移入一级缓存**: 当Bean完全初始化完成后,将其从二级缓存移至一级缓存,成为可供应用使用的完整Bean。 Spring通过3级缓存和早期引用策略,成功地解决了单例Bean的循环依赖问题,保证了程序的正常运行。理解这一机制有助于我们更好地设计和优化应用程序,避免潜在的性能和内存泄漏问题。