三层缓存机制-Spring容器

三级缓存【源码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Nullable  
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 先从一级缓存(成品单例)中获取
Object singletonObject = this.singletonObjects.get(beanName);

// 2. 如果一级缓存中没有,且当前Bean正在创建中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
// 2.1 从二级缓存(早期单例)中获取
singletonObject = this.earlySingletonObjects.get(beanName);

// 2.2 如果二级缓存中没有,且允许早期引用
if (singletonObject == null && allowEarlyReference) {
// 加锁保证线程安全
if (!this.singletonLock.tryLock()) {
return null;
}

try {
// 双重检查:再次从一级缓存确认
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 再次从二级缓存确认
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 3. 从三级缓存(单例工厂)中获取工厂
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 3.1 通过工厂生成早期实例
singletonObject = singletonFactory.getObject();
// 3.2 从三级缓存移除工厂,将实例放入二级缓存
if (this.singletonFactories.remove(beanName) != null) {
this.earlySingletonObjects.put(beanName, singletonObject);
} else {
// 兜底:再次从一级缓存获取(防止并发问题)
singletonObject = this.singletonObjects.get(beanName);
}
}
}
}
} finally {
// 释放锁
this.singletonLock.unlock();
}
}
}

return singletonObject;
}

源码

图解:
2025-10-14_20-38-50-0.png
单例对象池【成品区】
早期单例对象池【半成品区】
单例工厂【实现了ObjectFactory接口的】

2025-10-14_19-55-41-0.png

Spring 的三层缓存机制是解决单例 Bean 循环依赖的核心方案,通过三级缓存分层存储不同状态的 Bean 实例,既保证了单例唯一性,又避免了循环依赖导致的死锁或实例不完整问题。

三层缓存从上到下(查询顺序)依次是:

  1. 一级缓存(singletonObjects)

    • 存储完全初始化完成的单例 Bean 实例(已注入依赖、执行完初始化方法)。
    • 这是最终可用的 “成品” 缓存,优先查询,命中即返回。
  2. 二级缓存(earlySingletonObjects)

    • 存储已实例化但未完全初始化的单例 Bean 实例(如刚创建对象,还没注入依赖)。
    • 是 “半成品” 缓存,用于临时存放提前暴露的实例,解决循环依赖时的临时引用。
  3. 三级缓存(singletonFactories)

    • 存储单例 Bean 的工厂对象(ObjectFactory),工厂的作用是生成 Bean 的早期实例(放入二级缓存)。
    • 当 Bean 实例化后,Spring 会创建一个工厂并放入此缓存,延迟生成早期实例,避免不必要的提前暴露。

核心流程(以 A 依赖 B,B 依赖 A 为例):

  1. A 实例化后,将生成 A 的工厂放入三级缓存。
  2. A 需要注入 B,此时去创建 B。
  3. B 实例化后,将生成 B 的工厂放入三级缓存。
  4. B 需要注入 A,从三级缓存取出 A 的工厂,生成 A 的早期实例放入二级缓存,同时移除三级缓存的 A 工厂。
  5. B 注入 A 后完成初始化,放入一级缓存。
  6. A 注入 B 后完成初始化,放入一级缓存,同时移除二级缓存的 A 早期实例。

一句话记忆

三级缓存 “工厂造半成品,二级存半成品,一级存成品”,通过分层缓存解决了循环依赖中 “先有鸡还是先有蛋” 的问题。