news 2026/9/3 4:17:09

一文讲清楚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/9/2 10:43:04

26、MSMQ COM 组件编程全解析

MSMQ COM 组件编程全解析 1. MSMQ COM 组件概述 MSMQ 提供了十个 COM 组件,这些组件的功能与 MSMQ C 语言 API 相同,涵盖队列查找、队列管理、消息管理、队列管理和事务处理等方面。以下是这些组件及其功能的详细列表: | 组件 | 功能 | | — | — | | MSMQApplication …

作者头像 李华
网站建设 2026/9/2 10:15:29

27、深入探索排队组件:原理、实践与优化

深入探索排队组件:原理、实践与优化 排队组件概述 排队组件在外观和使用感受上与其他COM组件并无二致。客户端应用程序对排队对象进行方法调用的方式和普通COM对象类似,不过其底层架构能够对这些方法调用进行排队处理。 开发排队组件十分简单。你可以按照习惯的方式,使用…

作者头像 李华
网站建设 2026/9/2 20:39:12

CSS容器查询:让组件学会“见机行事“的魔法

最近在给编辑器做工具栏时&#xff0c;被一个优雅的CSS新特性惊艳到了——当工具栏空间不足时&#xff0c;时间信息自动隐藏&#xff1b;侧边栏收起后&#xff0c;它又神奇地出现。这不是JavaScript的功劳&#xff0c;而是CSS容器查询&#xff08;Container Queries&#xff09…

作者头像 李华
网站建设 2026/9/3 3:04:09

Spring Boot 学习心得:从配置繁琐到开发高效的蜕变

接触 Spring Boot 前&#xff0c;我用传统 Spring 框架开发项目时&#xff0c;常被海量 XML 配置、依赖版本冲突搞得焦头烂额。通过系统课程学习后&#xff0c;我不仅掌握了 Spring Boot 的核心用法&#xff0c;更在编程思路上完成了从 “配置驱动” 到 “约定优于配置” 的转变…

作者头像 李华
网站建设 2026/9/2 10:19:54

探索DY溢出指数模型:基于多种模型的实证之旅

DY溢出指数模型:基于DCC-GARCH&#xff0c;VAR&#xff0c;LASSO VAR,Ridge VAR,ElasticNet VAR,QVAR和TVP-VAR模型的dy溢出指数计算&#xff0c;只需提供数据&#xff0c;商家提供实证结果(以Excel形式提供)在金融领域&#xff0c;理解变量之间的动态溢出效应对于风险管理和投…

作者头像 李华
网站建设 2026/9/2 17:56:17

负氧离子传感器:实时跟踪负氧离子浓度变化

负氧离子传感器是一种能够实时监测空气中负氧离子浓度的设备&#xff0c;广泛应用于空气质量监测、环境评估、健康研究以及旅游景区管理等领域。以下是对负氧离子传感器的详细介绍&#xff1a;一、工作原理负氧离子传感器主要基于以下两种原理进行工作&#xff1a;电容式吸入法…

作者头像 李华