news 2026/1/8 20:17:21

一文讲清楚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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/29 3:55:12

24、COM+ 事务管理与补偿资源管理器详解

COM+ 事务管理与补偿资源管理器详解 1. 资源管理器(Resource Managers) COM+ 作为一种基础架构,需要以通用方式处理任何资源,而无需了解具体资源的细节。为了以通用方式访问和修改资源的持久状态,COM+ 依赖于资源管理器(RM)这一软件组件。 RM 对特定类型的资源(如关…

作者头像 李华
网站建设 2025/12/31 7:52:36

YOLO深度学习模型的训练参数配置与优化

一、总览 def parse_opt(known=False):parser = argparse.ArgumentParser()parser.add_argument(--weights, type=str, default=ROOT / yolov5s.pt, help=initial weights path)parser.add_argument(--cfg, type=str, default=, help=model.yaml path)parser.add_argument(--d…

作者头像 李华
网站建设 2026/1/3 23:39:53

数字孪生可视化模板怎么用?5大行业Demo拆解,帮你快速复用提效

在数字化转型加速推进的当下&#xff0c;数字孪生可视化已成为各行业提升运营效率、优化决策质量的核心工具。但对多数用户而言&#xff0c;新上架的可视化模板往往存在“看着好、用着难”的问题——不熟悉业务板块适配逻辑、不清楚配置要点&#xff0c;导致模板复用效率大打折…

作者头像 李华
网站建设 2026/1/7 21:14:39

必藏!程序员转型AI大模型:机遇、路径与成功率拆解

在程序员圈子里&#xff0c;“技术转型"从来都是绕不开的热门话题。尤其是ChatGPT引爆AI浪潮后&#xff0c;大模型技术以肉眼可见的速度重塑产业格局——从代码生成工具Copilot到智能客服系统&#xff0c;从数据分析平台到自动驾驶决策层&#xff0c;处处都有大模型的身影…

作者头像 李华
网站建设 2025/12/31 16:02:45

如何将照片从 Android 传输到 Android

您还在为将照片从 Android 传输到 Android 而苦苦挣扎吗&#xff1f;您现在可以轻松解决此问题。有 5 种有效的方法可以帮助您在 Android 设备之间传输图片。让我们来看看。第 1 部分&#xff1a;如何一键将照片从 Android 传输到 Android如何一键将照片从一部手机传输到另一部…

作者头像 李华