news 2026/7/12 0:38:46

一文讲清楚Spring中的三级缓存(附完整流程演示)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文讲清楚Spring中的三级缓存(附完整流程演示)

01-三级缓存的核心目的

Spring 三级缓存主要解决两个核心问题:

  • 单例 Bean 的循环依赖问题:Bean A 依赖 Bean B,Bean B 又依赖 Bean A
  • AOP代理与循环依赖的兼容问题:在循环依赖场景下,如何确保注入的是正确的代理对象

02-三级缓存的完整定义

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { // 第一级缓存:完全初始化好的单例Bean private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 第二级缓存:提前暴露的单例Bean(已实例化但未完成初始化) private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16); // 第三级缓存:单例工厂(用于创建Bean的早期引用,可能包含代理对象) private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16); // 正在创建中的Bean名称集合 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 已注册的单例Bean名称集合 private final Set<String> registeredSingletons = new LinkedHashSet<>(256); }

03-各级缓存详细说明

3.1 一级缓存:singletonObjects

一级缓存存储完全初始化完成的 Bean 实例

特点:

  • Bean 已经完成了所有初始化步骤:
    • 实例化(调用构造方法)
    • 属性填充(@Autowired 注入)
    • 初始化(@PostConstruct、InitializingBean)
    • 如果有 AOP 代理,存储的是代理对象
  • 线程安全,支持并发访问
  • 存储的 Bean 可以直接被应用程序使用

3.2二级缓存:earlySingletonObjects

二级缓存存储提前暴露的 Bean 实例已实例化但未完成属性注入

特点:

  • Bean 已经实例化,但尚未完成属性注入
  • 主要是为了解决循环依赖临时存储
  • 如果 Bean 需要 AOP 代理,这里存储的是代理对象
  • 从三级缓存的 ObjectFactory 创建后移入二级缓存

3.3 三级缓存:singletonFactories

三级缓存存储ObjectFactory 工厂对象,用于创建 Bean 的早期引用

特点

  • 存储的是ObjectFactory<?>不是 Bean 实例
  • 调用getObject()方法可以创建 Bean 的早期引用
  • 核心作用:解决 AOP 代理与循环依赖的结合问题
  • 在 Bean 实例化后、属性注入前放入

04-三级缓存的关键方法详解

4.1addSingletonFactory():添加三级缓存

将创建 Bean 的工厂放入三级缓存,为循环依赖提供出口

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { // 放入三级缓存 this.singletonFactories.put(beanName, singletonFactory); // 从二级缓存移除(保证数据一致性) this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }

4.2 getSingleton():获取单例Bean

涉及所有三级缓存:按 1→2→3 顺序查找

三级缓存的查询逻辑:

protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 快速检查一级缓存(完全初始化的Bean) Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 检查二级缓存(提前暴露的Bean) singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 检查三级缓存(Bean工厂) ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 调用工厂方法获取Bean的早期引用 singletonObject = singletonFactory.getObject(); // 将获取到的Bean放入二级缓存 this.earlySingletonObjects.put(beanName, singletonObject); // 从三级缓存移除 this.singletonFactories.remove(beanName); } } } } return singletonObject; }

4.3 getEarlyBeanReference():获取早期Bean引用

从三级缓存 获取工厂时调用,生成早期引用(可能是代理对象)

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; // 如果BeanDefinition不是合成的(非基础设施Bean)且存在InstantiationAwareBeanPostProcessor if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; // 关键:后置处理器可能返回代理对象 exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }

05-完整流程演示:A ↔ B 循环依赖 + AOP

假设有两个Service,且A需要AOP代理:

@Service @Transactional // A需要事务代理 public class ServiceA { @Autowired private ServiceB serviceB; public void methodA() { // 业务逻辑 } } @Service public class ServiceB { @Autowired private ServiceA serviceA; public void methodB() { // 业务逻辑 } }

详细执行流程:

06-注意事项

6.1 构造器注入无法使用三级缓存

构造器调用时对象还未创建,无法放入三级缓存,因此无法解决循环依赖。

@Component public class ServiceA { private final ServiceB serviceB; @Autowired // 构造器注入 public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; // 构造时就依赖B,但B可能还未创建 // 此时ServiceA还未实例化完成,ServiceA 无法放入三级缓存 } }

6.2 原型Bean的循环依赖

原型Bean不放入三级缓存,每次请求都创建新实例

@Scope("prototype") @Component public class PrototypeA { @Autowired private PrototypeB b; } @Scope("prototype") @Component public class PrototypeB { @Autowired private PrototypeA a; }

Spring会直接抛出异常:BeanCurrentlyInCreationException: Error creating bean with name 'prototypeA': Requested bean is currently in creation

6.3 @Async方法的特殊处理

@Async也是通过AOP实现的,但处理时机不同;
需要在initializeBean阶段创建代理,可能影响循环依赖

@Service public class AsyncService { @Async public void asyncMethod() { // 异步方法 } @Autowired private AnotherService anotherService; }

07-总结

缓存级别存储内容生命周期主要作用
一级缓存完全初始化的BeanBean整个生命周期提供最终可用的Bean
二级缓存早期Bean(已实例化未初始化)创建过程中临时存在解决循环依赖,避免重复创建
三级缓存ObjectFactory工厂对象Bean实例化后到初始化前处理AOP代理,确保返回正确的代理对象

核心思想:通过懒加载的ObjectFactory延迟决策,只有在真正发生循环依赖时才创建代理对象,既解决了循环依赖问题,又保持了Bean生命周期的完整性,同时支持AOP等增强功能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/10 5:26:49

28、分布式计算中的事件通知机制解析

分布式计算中的事件通知机制解析 1. 分布式计算中的事件通知需求 在分布式计算环境中,向感兴趣的各方通知数据变更情况是一项常见需求。例如,股票行情程序需向客户端通知股价变化;计算机监控程序要告知管理员系统状态;病毒检测程序在检测到病毒时需警告用户;医疗监控程序…

作者头像 李华
网站建设 2026/7/9 4:51:54

30、COM+ 技术助力企业应用可扩展性提升

COM+ 技术助力企业应用可扩展性提升 1. 事件系统概述 事件是对某些重要数据变化的通知。发布者触发事件,一个或多个订阅者接收该事件。事件系统实现大致可分为紧密耦合事件(TCEs)和松散耦合事件(LCEs)两类。 事件类型 特点 示例 紧密耦合事件(TCEs) 发布者和订阅…

作者头像 李华
网站建设 2026/7/10 23:01:48

运维系列数据库系列【仅供参考】:达梦数据库:DM8锁等待和死锁

达梦数据库:DM8锁等待和死锁 DM8锁等待和死锁 DM事务锁 锁等待 场景一:INSERT锁等待 02 锁等待解决方法 死锁 测试场景如下: DDL锁超时 DM8锁等待和死锁 DM事务锁 创建测试表 create table t_test01(id int primary key, name varchar(20)); select * from t_test01; sel…

作者头像 李华
网站建设 2026/7/11 7:37:20

运维系列数据库系列【仅供参考】:达梦:DM8归档日志挖掘

达梦:DM8归档日志挖掘 DM8归档日志挖掘 一、配置源数据库 二、源数据库模拟数据操作 三、配置本地数据库 01修改dm.ini参数并配置归档 02查询本地魔数 03下载源端归档日志到本地(不要使用xftp下载,会损坏日志 04修改归档日志魔数(依次修改三个归档日志魔数) 05添加归档日志…

作者头像 李华
网站建设 2026/7/9 0:55:35

综合型系统集成商:高端会议室从 “能用” 到 “好用” 的核心赋能者

在高端会议室改造中&#xff0c;系统稳定性、场景适配性与用户体验是核心诉求&#xff0c;需围绕扩声、信号处理、集中控制、无纸化等关键模块选择适配设备。GONSIN 公信会议作为聚焦高端会议场景的综合型系统集成商&#xff0c;其产品体系可针对性解决高端会议室常见的声场不均…

作者头像 李华