Spring中的三级缓存及其原因

本文详细介绍了Spring中解决循环依赖的三级缓存机制:singletonObjects(一级缓存),singletonFactories(二级缓存)和earlySingletonObjects(三级缓存)。通过分析不使用AOP时的二级缓存处理流程和使用AOP时引入三级缓存的原因,阐述了三级缓存在处理循环依赖和确保对象正确代理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先看下Spring创建一个bean的基本流程:

创建该实例的原始对象 --> 进行自动装配 --> AOP代理处理 --> 完成bean的创建并加入单例池(即一级缓存)

但是当有循环依赖的时候,Spring是如何解决的呢?

主要原理是利用三级缓存机制:
在这里插入图片描述

singletonObjects: 一级缓存,也就是我们平常理解的单例池。
singletonFactories: 二级缓存,存储的是单例工厂。
earlySingletonObjects: 三级缓存,存储正在创建中的单例对象。
为什么要设立三级缓存呢?

其实当不需要实现AOP的时候,解决循环依赖不用三级缓存机制,也不用单例工厂,二级缓存就足以实现。

第一级:singletonObjects
第二级:earlySingletonObjects

不需要实现AOP时Spring解决循环依赖基本流程:

假设单例一与单例二相互依赖对方并且此时都没有加入到单例池
1 创建单例一
2 将单例一加入earlySingletonObjects缓存
3 自动装配单例二
4 判断单例二在earlySingletonObjects缓存是否存在
5 不存在则创建单例二
6 将单例二并且加入earlySingletonObjects缓存
7 自动装配单例一
8 判断单例一在earlySingletonObjects缓存是否存在
9 明显第2步已经加入earlySingletonObje

<think>好的,我现在需要详细分析Spring框架中的三级缓存机制,包括它的实现机制和作用原理。首先,我需要回忆一下用户提供的引用内容,特别是引用[1]、[3]中的信息,这些提到了三级缓存用于解决循环依赖和支持AOP。 首先,三级缓存是什么?根据引用[1]和[3],Spring三级缓存包括三个不同的缓存层,可能分别是singletonObjects、earlySingletonObjects和singletonFactories。每个缓存的作用是什么呢? 接下来,我需要理解Bean的创建过程。根据引用[3],Bean的生命周期包括实例化、属性填充、初始化等阶段。在解决循环依赖时,当Bean A依赖Bean B,而Bean B又依赖Bean A时,Spring需要确保两者都能正确创建。这时,三级缓存中的机制可能是在Bean实例化后,提前暴露一个对象引用,避免无限循环。 然后,三级缓存的具体实现机制。根据引用[3],一级缓存singletonObjects存完全初始化的Bean,二级缓存earlySingletonObjects存早期暴露的对象三级缓存singletonFactories存生成早期对象工厂。当创建Bean时,Spring首先检查一级缓存,如果没有,则检查二级缓存,再没有的话,使用三级缓存中的工厂创建早期对象,并将其入二级缓存。这样,当其他Bean需要依赖当前Bean时,可以获取到早期的引用,完成属性注入,从而解决循环依赖。 此外,三级缓存如何支持AOP?可能是在创建代理对象时,需要确保代理的一致性。如果Bean被AOP代理,那么提前暴露的应该是代理对象而不是原始对象。通过三级缓存中的工厂Spring可以在需要时生成代理对象,保证在循环依赖中注入的是最终的代理对象,而不是原始对象,从而避免不一致的问题。 现在需要验证这些理解是否正确。根据引用[1],三级缓存用于处理实例化和依赖注入,确保循环依赖下正确创建Bean。引用[3]指出三级缓存解决了循环依赖和AOP的支持。因此,我的理解应该是正确的。 最后,总结三级缓存的工作流程:创建Bean时,先实例化,然后三级缓存;当需要注入依赖时,从三级缓存获取工厂生成早期对象,并将其升级到二级缓存;完成属性填充和初始化后,入一级缓存,并清理下级缓存。这样既解决了循环依赖,又处理了AOP代理的问题。</think>### Spring框架三级缓存实现机制及作用原理 #### 一、三级缓存的定义与作用 Spring框架通过**三级缓存**解决**循环依赖**问题,并支持**AOP代理对象**的一致性。三级缓存具体分为: 1. **一级缓存(`singletonObjects`)** 存储**完全初始化**的单例Bean,可直接使用。 2. **二级缓存(`earlySingletonObjects`)** 存储**早期暴露的Bean实例**(已实例化但未完成属性注入和初始化)。 3. **三级缓存(`singletonFactories`)** 存储**Bean工厂对象**(`ObjectFactory`),用于生成早期Bean的引用。 #### 二、实现机制与流程 以Bean A和Bean B相互依赖为例: 1. **创建Bean A** - **实例化**:调用构造器创建Bean A的原始对象`a`。 - **提前暴露引用**:将`a`的工厂(`ObjectFactory`)存入**三级缓存**。 $$ \text{三级缓存:A → ObjectFactory(a)} $$ 2. **填充Bean A的属性** - 发现依赖Bean B,触发**Bean B的创建**。 3. **创建Bean B** - 实例化Bean B的原始对象`b`,将其工厂存入三级缓存。 - 填充Bean B的属性时,发现依赖Bean A,尝试从**一级缓存**获取A。 - 未找到A,从**三级缓存**获取A的工厂,生成早期对象`a'`,将`a'`升级到**二级缓存**并清理三级缓存。 $$ \text{二级缓存:A → a'} $$ - Bean B完成初始化后存入一级缓存。 4. **继续初始化Bean A** - 从二级缓存获取`a'`,完成属性注入和初始化。 - 将Bean A存入一级缓存,清理二级缓存。 #### 三、关键设计点 1. **循环依赖的解决** - 通过**提前暴露半成品Bean**(三级缓存工厂)打破循环链。 2. **AOP代理的支持** - 若Bean需要代理,三级缓存工厂会返回**代理对象**而非原始对象,确保依赖注入的一致性[^3]。 - 例如,若Bean A需代理,则工厂生成的`a'`是代理对象,避免后续流程出现原始对象与代理对象混合的问题。 #### 四、流程图解 ```plaintext 创建Bean A → 实例化 → 存入三级缓存 → 填充属性(发现依赖B) ↓ 创建Bean B → 实例化 → 存入三级缓存 → 填充属性(发现依赖A) ↓ 从三级缓存获取A的工厂 → 生成A的早期对象 → 存入二级缓存 ↓ Bean B完成初始化 → 存入一级缓存 ↓ 继续初始化Bean A → 从二级缓存获取 → 完成 → 存入一级缓存 ``` #### 五、典型问题场景 1. **仅两级缓存能否解决循环依赖?** - 无法处理AOP代理场景,可能导致注入原始对象而非代理对象。 2. **为什么三级缓存使用`ObjectFactory`?** - 延迟生成代理对象,仅在需要时通过工厂创建,避免重复生成[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值