spring三级缓存
三级缓存分别是:一级缓存初始化后的bean,二级缓存bean的早期应用即刚实例化没有依赖注入的bean,三级缓存的是bean工厂。
假设AB循环依赖,A在创建过程中发现需要B,转而去创建B;B在创建过程中发现需要A,此时获取到A的早期引用注入到B中,B完成创建后,A再注入完整的B,从而解决循环依赖。
理论上一级二级就能解决循环依赖,而第三级是为了处理aop代理的情况。
Spring三级缓存详解
Spring在DefaultSingletonBeanRegistry中维护了三个缓存,用于存储不同阶段的Bean:
一级缓存:singletonObjects
存储对象:完全初始化好的单例Bean
特点:Bean已经完成了实例化、属性注入、初始化,可以直接使用
数据结构:
Map<String, Object>
二级缓存:earlySingletonObjects
存储对象:提前暴露的早期Bean(还未完成属性注入和初始化)
特点:Bean已经实例化,但还未进行属性填充和初始化,解决的是"提前暴露"的问题
数据结构:
Map<String, Object>
三级缓存:singletonFactories
存储对象:单例Bean工厂
特点:存放的是
ObjectFactory,可以生成早期Bean的引用数据结构:
Map<String, ObjectFactory<?>>
工作流程示例
假设A依赖B,B依赖A:
创建A:实例化A,将A的
ObjectFactory放入三级缓存填充A:发现需要B,去创建B
创建B:实例化B,将B的
ObjectFactory放入三级缓存填充B:发现需要A,从三级缓存获取A的
ObjectFactory,生成A的早期引用放入二级缓存,注入到BB完成初始化:B初始化完成后放入一级缓存
A继续初始化:A从一级缓存获取B,完成属性注入和初始化,放入一级缓存
是否还要手动解决循环依赖
Spring的三级缓存已经帮我们解决了绝大多数的循环依赖问题,日常开发中你不需要手动干预。但在构造器注入、原型Bean等特殊场景下,仍然需要注意避免循环依赖的产生。最好的实践是尽量避免循环依赖,因为它往往暗示着设计上可能存在一些问题。
