spring三级缓存

Spring 的 三级缓存(Three-level Cache) 主要应用在 Spring Bean 的实例化 过程中,用于 解决循环依赖。这是 Spring IoC 容器的核心机制之一,特别是在 单例模式(Singleton Scope) 下。


Spring 三级缓存

Spring 在 DefaultSingletonBeanRegistry 中定义了三级缓存:

  1. singletonObjects(一级缓存):存放 完全实例化的 Bean,即 创建完成且初始化完成 的 Bean。

  2. earlySingletonObjects(二级缓存):存放 创建完成但未进行初始化的 Bean,主要用于解决 循环依赖

  3. singletonFactories(三级缓存):存放 Bean 的 ObjectFactory,用于在必要时 提前曝光 Bean 实例,解决代理对象的循环依赖


三级缓存的作用

主要作用是

  1. 避免重复创建 Bean,提升 Bean 复用率。

  2. 解决循环依赖(特别是 AOP 代理场景)。

  3. 优化性能,减少不必要的锁竞争


Spring 三级缓存源码解析

核心逻辑在 AbstractAutowireCapableBeanFactory#doCreateBean() 方法中,简化流程如下:

1. 创建 Bean 实例

// 获取 bean 的定义信息
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

// 创建 bean 实例(只创建对象,不初始化)
Object beanInstance = createBeanInstance(beanName, mbd, args);

此时,Bean 只是被实例化,但尚未初始化。


2. 放入三级缓存(singletonFactories)

// 提前暴露一个 ObjectFactory(用于 AOP 代理)
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));
  • addSingletonFactory():将 ObjectFactory 放入 三级缓存 singletonFactories

  • getEarlyBeanReference():如果有 AOP 代理,这里会返回代理对象。


3. 解决循环依赖(从三级缓存提升到二级缓存)

若其他 Bean 依赖此 Bean,则会尝试从缓存获取:

// 尝试从二级缓存 earlySingletonObjects 获取实例
earlySingleton = this.earlySingletonObjects.get(beanName);
if (earlySingleton == null) {
    // 若二级缓存没有,则调用 ObjectFactory 从三级缓存创建 Bean
    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    if (singletonFactory != null) {
        earlySingleton = singletonFactory.getObject();
        this.earlySingletonObjects.put(beanName, earlySingleton);
        this.singletonFactories.remove(beanName);
    }
}
  • 如果一个 Bean 依赖另一个未初始化的 Bean,Spring 会先去二级缓存 earlySingletonObjects 取实例。

  • 如果二级缓存没有,则会从 三级缓存 singletonFactories 中调用 ObjectFactory#getObject() 创建实例,并存入二级缓存。

  • 最后从三级缓存移除,避免重复创建。


4. 完成 Bean 初始化,移入一级缓存

// Bean 初始化完成后,放入一级缓存,并移除二级缓存
this.singletonObjects.put(beanName, bean);
this.earlySingletonObjects.remove(beanName);
  • 一级缓存 singletonObjects 存放 完全初始化的 Bean,用于最终获取实例。


Spring 三级缓存解决循环依赖的示例

循环依赖场景

@Component
public class A {
    @Autowired
    private B b;
}

@Component
public class B {
    @Autowired
    private A a;
}

A 依赖 BB 依赖 A,如果没有三级缓存,会导致 StackOverflowError


三级缓存的作用

  1. Spring 发现 A 需要 B,开始创建 A

  2. 在实例化 A 后,将 A 放入三级缓存(但尚未初始化)。

  3. Spring 发现 A 依赖 B,开始创建 B

  4. 在实例化 B 后,发现 B 依赖 A,从三级缓存获取 A 并注入

  5. B 完成创建,并初始化 A,最终 AB 都被放入一级缓存。


为什么 Spring 需要三级缓存?

如果只有二级缓存,无法解决 AOP 代理的循环依赖问题!

  • 二级缓存(earlySingletonObjects) 只能存 原始对象,但 AOP 需要代理对象

  • 三级缓存(singletonFactories) 允许通过 getEarlyBeanReference() 生成代理对象。

  • 当 AOP 代理存在时,Spring 直接返回代理对象,保证最终 AB 的依赖一致。


总结

  • 一级缓存 singletonObjects:存放 完全初始化的 Bean,最终可用的单例对象。

  • 二级缓存 earlySingletonObjects:存放 实例化但未初始化的 Bean,用于解决普通循环依赖

  • 三级缓存 singletonFactories:存放 ObjectFactory,用于 AOP 代理或特殊情况

三级缓存的作用

提高 Bean 复用率,避免重复创建
解决 Spring 单例 Bean 的循环依赖问题
支持 AOP 代理的提前曝光,保证代理对象的正确注入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值