三级缓存【源码】
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) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { singletonObject = this.earlySingletonObjects.get(beanName); 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) { ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); if (this.singletonFactories.remove(beanName) != null) { this.earlySingletonObjects.put(beanName, singletonObject); } else { singletonObject = this.singletonObjects.get(beanName); } } } } } finally { this.singletonLock.unlock(); } } } return singletonObject; }
|

图解:

单例对象池【成品区】
早期单例对象池【半成品区】
单例工厂【实现了ObjectFactory接口的】

Spring 的三层缓存机制是解决单例 Bean 循环依赖的核心方案,通过三级缓存分层存储不同状态的 Bean 实例,既保证了单例唯一性,又避免了循环依赖导致的死锁或实例不完整问题。
三层缓存从上到下(查询顺序)依次是:
一级缓存(singletonObjects)
- 存储完全初始化完成的单例 Bean 实例(已注入依赖、执行完初始化方法)。
- 这是最终可用的 “成品” 缓存,优先查询,命中即返回。
二级缓存(earlySingletonObjects)
- 存储已实例化但未完全初始化的单例 Bean 实例(如刚创建对象,还没注入依赖)。
- 是 “半成品” 缓存,用于临时存放提前暴露的实例,解决循环依赖时的临时引用。
三级缓存(singletonFactories)
- 存储单例 Bean 的工厂对象(ObjectFactory),工厂的作用是生成 Bean 的早期实例(放入二级缓存)。
- 当 Bean 实例化后,Spring 会创建一个工厂并放入此缓存,延迟生成早期实例,避免不必要的提前暴露。
核心流程(以 A 依赖 B,B 依赖 A 为例):
- A 实例化后,将生成 A 的工厂放入三级缓存。
- A 需要注入 B,此时去创建 B。
- B 实例化后,将生成 B 的工厂放入三级缓存。
- B 需要注入 A,从三级缓存取出 A 的工厂,生成 A 的早期实例放入二级缓存,同时移除三级缓存的 A 工厂。
- B 注入 A 后完成初始化,放入一级缓存。
- A 注入 B 后完成初始化,放入一级缓存,同时移除二级缓存的 A 早期实例。
一句话记忆:
三级缓存 “工厂造半成品,二级存半成品,一级存成品”,通过分层缓存解决了循环依赖中 “先有鸡还是先有蛋” 的问题。