当前位置: 首页 > news >正文

Spring的三级缓存原理 笔记251008

Spring的三级缓存原理 笔记251008

在这里插入图片描述

  • 一级缓存存储: 完成实例化,完成属性注入 的Bean
  • 二级缓存存储: 完成实例化,未完成属性注入 的Bean
  • 三级缓存存储: Bean的工厂 (Bean还没有实例化)

Spring 的三级缓存是 Singleton 三级缓存体系,用于解决 循环依赖 问题,尤其是 单例 Bean 的循环依赖。它的核心思想是:提前暴露未完全初始化的 Bean 的引用,让其他 Bean 可以先引用它,从而打破循环依赖的死锁。


    ✅ 三级缓存的结构(DefaultSingletonBeanRegistry)

Spring 的三级缓存是在 DefaultSingletonBeanRegistry 中定义的,分别是:

缓存名称变量名作用
一级缓存singletonObjects存放 完全初始化好 的单例 Bean(最终成品)
二级缓存earlySingletonObjects存放 提前暴露 的单例 Bean(半成品,已实例化但未初始化)
三级缓存singletonFactories存放 ObjectFactory,用于生成早期引用(支持 AOP 代理)

    ✅ 三级缓存解决循环依赖的流程

假设有两个 Bean:A 和 B,它们互相依赖:

class A {@Autowiredprivate B b;
}class B {@Autowiredprivate A a;
}

        步骤如下:

  1. 创建 A 的实例(构造函数)→ 完成实例化,但未初始化。
  2. 将 A 的 ObjectFactory 放入三级缓存singletonFactories)。
  3. 填充 A 的属性 → 发现需要 B。
  4. 创建 B 的实例 → 完成实例化,未初始化。
  5. B 填充属性 → 发现需要 A。
  6. 从三级缓存中获取 A 的 ObjectFactory,调用 getObject() 获取早期引用(可能是代理对象),放入二级缓存。
  7. B 完成初始化 → 放入一级缓存。
  8. A 继续填充属性 → 拿到 B 的完整对象。
  9. A 完成初始化 → 放入一级缓存。

    ✅ 为什么需要三级缓存?二级不行吗?

  • 二级缓存(earlySingletonObjects) 只能存 Bean 的早期引用。
  • 三级缓存(singletonFactories) 存的是 ObjectFactory,可以 延迟创建代理对象,支持 AOP 代理

如果只有二级缓存,AOP 代理对象必须在实例化后立即创建,这违反了 Spring 的设计原则(代理在初始化后创建)。
三级缓存通过 ObjectFactory.getObject() 延迟创建代理,保证了 生命周期一致性


    ✅ 总结一句话

三级缓存的核心作用是:通过提前暴露 ObjectFactory,支持循环依赖,并保证 AOP 代理的正确创建时机。


    ✅ 图示(简化)

singletonObjects(一级) ← 最终成品
↑
earlySingletonObjects(二级) ← 早期引用(从三级缓存拿)
↑
singletonFactories(三级) ← ObjectFactory(延迟创建代理)

    ✅ 注意

  • 仅支持单例 Bean 的循环依赖
  • 原型 Bean(prototype)不支持循环依赖,会直接抛异常。
  • 构造器注入的循环依赖无法解决(因为实例化阶段就卡住了)。

需要我帮你画个流程图或贴源码分析吗?

Spring 三级缓存原理详解

1. 循环依赖问题与三级缓存的引入

1.1 循环依赖问题

@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Service 
public class OrderService {@Autowiredprivate UserService userService;
}

上述代码会产生循环依赖:UserServiceOrderServiceUserService

1.2 三级缓存的作用

Spring 通过三级缓存机制解决单例 Bean 的循环依赖问题。

2. 三级缓存定义与层次

2.1 三级缓存定义

DefaultSingletonBeanRegistry 类中定义:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象(尚未完成属性填充)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的 Bean 名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

2.2 缓存层次说明

缓存级别存储内容作用
一级缓存完全初始化好的 Bean提供完整的 Bean 实例
二级缓存早期对象(未完成属性填充)解决循环依赖,避免重复创建代理
三级缓存ObjectFactory 工厂对象创建早期引用,支持 AOP 代理

3. Bean 创建流程与缓存交互

3.1 Bean 创建的核心流程

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1. 实例化Object beanInstance = instantiateBean(beanName, mbd);// 2. 添加到三级缓存(解决循环依赖的关键)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));// 3. 属性填充(可能触发循环依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}

3.2 三级缓存的添加时机

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. 循环依赖解决流程

4.1 详细解决流程

// 获取 Bean 的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存查找singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存获取 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过工厂创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,从三级缓存移除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

4.2 循环依赖解决示例

UserServiceOrderService 为例:

// UserService 创建过程
1. 开始创建 UserService
2. 实例化 UserService(原始对象)
3.UserServiceObjectFactory 放入三级缓存
4. 属性填充:发现需要 OrderService
5. 开始创建 OrderService// OrderService 创建过程  
6. 实例化 OrderService(原始对象)
7.OrderServiceObjectFactory 放入三级缓存
8. 属性填充:发现需要 UserService
9. 获取 UserService- 一级缓存:无- 二级缓存:无  - 三级缓存:找到 UserServiceObjectFactory- 通过 ObjectFactory 获取 UserService 的早期引用-UserService 从三级缓存移到二级缓存
10. OrderService 完成属性填充和初始化
11. OrderService 放入一级缓存// 回到 UserService 创建
12. UserService 完成属性填充(注入 OrderService13. UserService 完成初始化
14. UserService 放入一级缓存,从二级缓存移除

5. AOP 代理与三级缓存

5.1 代理对象的特殊处理

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

5.2 AOP 代理场景示例

@Service
public class UserService {@Autowiredprivate OrderService orderService;@Transactionalpublic void updateUser() {// 事务方法}
}@Service
public class OrderService {@Autowiredprivate UserService userService;  // 这里需要注入代理对象
}

处理流程:

  1. UserService 实例化后,三级缓存中的 ObjectFactory 会检查是否需要 AOP 代理
  2. 如果需要代理,getEarlyBeanReference 返回代理对象
  3. OrderService 注入的是 UserService 的代理对象
  4. 保证事务等 AOP 功能正常工作

6. 源码深度解析

6.1 核心源码分析

public class DefaultSingletonBeanRegistry {public Object getSingleton(String beanName) {return getSingleton(beanName, true);}protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 第一级检查:完全初始化的 BeanObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 第二级检查:早期引用singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 第三级检查:ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 升级到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
}

6.2 Bean 创建完整流程

public abstract class AbstractAutowireCapableBeanFactory {protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化 BeanObject beanInstance = instantiateBean(beanName, mbd);// 2. 暴露早期引用(解决循环依赖的关键)boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {// 添加到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性填充(可能触发依赖注入)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);// 5. 处理早期引用暴露if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == beanInstance) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping) {// 处理包装情况}}}return exposedObject;}
}

7. 特殊情况处理

7.1 构造器循环依赖

@Service
public class UserService {private final OrderService orderService;// 构造器注入 - 无法通过三级缓存解决public UserService(OrderService orderService) {this.orderService = orderService;}
}@Service
public class OrderService {private final UserService userService;public OrderService(UserService userService) {this.userService = userService;}
}

结果:构造器循环依赖无法解决,Spring 会抛出 BeanCurrentlyInCreationException

7.2 原型模式的循环依赖

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
@Service
public class OrderService {@Autowiredprivate UserService userService;
}

结果:原型 Bean 的循环依赖无法解决,因为三级缓存只针对单例 Bean

8. 三级缓存的设计原理

8.1 为什么需要三级缓存?

一级缓存的作用

  • 存储完全初始化好的 Bean
  • 提供最终的单例实例

二级缓存的作用

  • 存储早期暴露的对象
  • 避免重复创建代理对象

三级缓存的作用

  • 存储创建 Bean 的工厂
  • 支持 AOP 代理等后处理器的介入

8.2 三级缓存的必要性

// 如果只有二级缓存,没有三级缓存:
// 在属性填充阶段,如果 Bean 需要被代理,我们无法知道应该返回原始对象还是代理对象// 三级缓存通过 ObjectFactory 延迟决策:
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {// 在这里决定返回原始对象还是代理对象singletonObject = singletonFactory.getObject();
}

9. 实际应用与调试

9.1 调试三级缓存

@Component
public class CacheDebugger implements ApplicationRunner {@Autowiredprivate AbstractApplicationContext context;@Overridepublic void run(ApplicationArguments args) throws Exception {DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) context.getBeanFactory();// 通过反射获取缓存内容printCacheInfo(registry, "singletonObjects");printCacheInfo(registry, "earlySingletonObjects"); printCacheInfo(registry, "singletonFactories");}private void printCacheInfo(DefaultSingletonBeanRegistry registry, String fieldName) {try {Field field = DefaultSingletonBeanRegistry.class.getDeclaredField(fieldName);field.setAccessible(true);Map<?, ?> cache = (Map<?, ?>) field.get(registry);System.out.println(fieldName + ": " + cache.keySet());} catch (Exception e) {e.printStackTrace();}}
}

9.2 循环依赖检测

@Component
public class CircularDependencyDetector {public void detectCircularDependencies(ConfigurableListableBeanFactory beanFactory) {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {try {// 尝试获取 Bean,触发循环依赖检测beanFactory.getBean(beanName);} catch (BeanCurrentlyInCreationException e) {System.out.println("发现循环依赖: " + e.getMessage());}}}
}

10. 性能优化与最佳实践

10.1 避免循环依赖

最佳实践

  1. 使用 setter 注入而非构造器注入
  2. 使用 @Lazy 注解延迟加载
  3. 重构代码,消除循环依赖

10.2 @Lazy 注解的使用

@Service
public class UserService {@Lazy  // 延迟注入,打破循环依赖@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowiredprivate UserService userService;
}

10.3 应用启动参数

# 禁用循环引用(不推荐,但可用于调试)
spring.main.allow-circular-references=false# 允许注入原始 Bean(即使有 AOP 包装)
spring.main.allow-bean-definition-overriding=true

总结

Spring 三级缓存机制的核心要点:

  1. 解决什么问题:单例 Bean 的循环依赖
  2. 核心思想:提前暴露未完全初始化的 Bean 引用
  3. 三级缓存分工
    • 一级缓存:完整的 Bean
    • 二级缓存:早期的 Bean 引用
    • 三级缓存:Bean 创建工厂
  4. 关键时机:实例化后、属性填充前添加到三级缓存
  5. 特殊处理:支持 AOP 代理等后处理器
  6. 限制条件:无法解决构造器循环依赖和原型 Bean 循环依赖

理解三级缓存原理对于深入掌握 Spring IoC 容器的工作机制、排查循环依赖问题以及进行性能优化都具有重要意义。

















1️⃣ 参考 1

Spring 三级缓存原理详解

1. 什么是三级缓存

Spring 的三级缓存是解决循环依赖问题的核心机制。它通过在 Bean 创建的不同阶段将 Bean 对象存储在不同的缓存中,从而允许其他 Bean 在依赖注入时能够获取到尚未完全初始化的 Bean 引用。

2. 三级缓存的具体定义

DefaultSingletonBeanRegistry 类中定义了三层缓存:

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 HashMap<>(16);// 正在创建中的 Bean 名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

3. Bean 的创建流程与三级缓存

    3.1 Bean 的完整生命周期

// 简化的 Bean 创建流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(调用构造函数)Object beanInstance = createBeanInstance(beanName, mbd, args);// 2. 将 Bean 工厂放入三级缓存(解决循环依赖的关键)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性注入populateBean(beanName, mbd, beanInstanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}

    3.2 三级缓存在循环依赖中的工作流程

假设有循环依赖:A → B → A

@Component
public class A {@Autowiredprivate B b;
}@Component  
public class B {@Autowiredprivate A a;
}

创建流程:

  1. 开始创建 A

    // A 开始创建,加入创建中集合
    singletonsCurrentlyInCreation.add("a");// 实例化 A 对象
    Object a = new A();// 将 A 的 ObjectFactory 放入三级缓存
    addSingletonFactory("a", () -> getEarlyBeanReference("a", mbd, a));
    
  2. A 进行属性注入,发现依赖 B

    // 在注入 B 时,会调用 getBean("b")
    // 此时 A 还在创建中,但已经在三级缓存中有工厂对象
    
  3. 开始创建 B

    singletonsCurrentlyInCreation.add("b");
    Object b = new B();
    addSingletonFactory("b", () -> getEarlyBeanReference("b", mbd, b));
    
  4. B 进行属性注入,发现依赖 A

    // 调用 getBean("a") 获取 A
    // 发现 A 正在创建中 (singletonsCurrentlyInCreation.contains("a"))// 从三级缓存获取 A 的早期引用
    Object aEarly = getSingleton("a", true);
    
  5. 获取 A 的早期引用流程

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找(完整 Bean)Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 2. 从二级缓存查找(早期 Bean)singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 3. 从三级缓存获取工厂并创建早期引用ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 将早期引用放入二级缓存,移除三级缓存中的工厂this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
    }
    
  6. B 完成创建

    // B 完成属性注入和初始化
    // 将 B 放入一级缓存,清除二三级缓存
    addSingleton("b", b);
    
  7. A 完成创建

    // A 继续完成属性注入(此时 B 已可用)
    // A 完成初始化,放入一级缓存
    addSingleton("a", a);
    

4. 三级缓存的具体作用

    4.1 一级缓存:singletonObjects

  • 作用:存放完全初始化好的单例 Bean
  • 特点:可直接使用的完整 Bean
  • 操作时机:Bean 完全创建完成后放入

    4.2 二级缓存:earlySingletonObjects

  • 作用:存放早期的 Bean 引用(已实例化但未完成初始化)
  • 特点:用于解决循环依赖中的"鸡生蛋"问题
  • 操作时机:从三级缓存升级而来

    4.3 三级缓存:singletonFactories

  • 作用:存放创建早期引用的工厂对象
  • 特点:延迟创建,只在需要时生成早期引用
  • 核心价值:处理 AOP 代理等特殊情况

5. 为什么需要三级缓存而不是两级?

    5.1 处理 AOP 代理的特殊情况

@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowired private A a;  // 这里需要的是 A 的代理对象,而不是原始对象
}@Configuration
@EnableAspectJAutoProxy
public class Config {@Beanpublic LoggingAspect loggingAspect() {return new LoggingAspect();}
}

三级缓存的关键代码:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能会返回代理对象而不是原始对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

    5.2 三级缓存的必要性

如果只有两级缓存:

  • 无法正确处理代理对象的循环依赖
  • 可能导致注入的对象与最终对象不一致

三级缓存通过 ObjectFactory 延迟创建,确保:

  • 在需要早期引用时才创建
  • 能够正确处理 AOP 代理等后处理器

6. 源码分析关键方法

    6.1 getSingleton 方法

public Object getSingleton(String beanName) {return getSingleton(beanName, true);
}protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 三级缓存查找逻辑// 1. 一级缓存 → 2. 二级缓存 → 3. 三级缓存
}

    6.2 addSingletonFactory 方法

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}
}

    6.3 addSingleton 方法

protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);}
}

7. 无法解决的循环依赖情况

    7.1 构造器循环依赖

@Component
public class A {private final B b;@Autowiredpublic A(B b) {  // 构造器注入,无法解决循环依赖this.b = b;}
}@Component
public class B {private final A a;@Autowired  public B(A a) {  // 构造器注入,无法解决循环依赖this.a = a;}
}

原因:构造器注入时,Bean 还未实例化,无法放入三级缓存。

    7.2 Prototype 作用域的循环依赖

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {@Autowiredprivate B b;  // Prototype 作用域,无法解决循环依赖
}

8. 总结

Spring 的三级缓存机制:

  1. 一级缓存:完整 Bean,可直接使用
  2. 二级缓存:早期 Bean,解决普通循环依赖
  3. 三级缓存:Bean 工厂,处理 AOP 代理等复杂情况

核心价值:通过分层缓存和延迟创建策略,优雅地解决了 Spring 中的循环依赖问题,同时保证了 Bean 创建的正确性和一致性。

设计思想:空间换时间,通过多级缓存平衡了性能与功能的矛盾,体现了 Spring 框架设计的精妙之处。

















2️⃣ 参考 2

Spring 三级缓存原理详解

概述

Spring 的三级缓存是解决循环依赖问题的核心机制。通过三级缓存的设计,Spring 能够在 Bean 创建过程中处理相互依赖的情况。

三级缓存定义

DefaultSingletonBeanRegistry 类中定义了三级缓存:

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的ObjectFactory(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);// 正在创建中的Bean名称private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

解决循环依赖的流程

    场景:A 依赖 B,B 依赖 A

@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}

    创建过程详解

        1. 开始创建 A

// 步骤1: 检查一级缓存
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存查找singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存获取ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过ObjectFactory创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,清除三级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

创建 A 的详细步骤:

  1. 实例化 A

    // 调用构造方法创建A实例
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    Object bean = instanceWrapper.getWrappedInstance();
    
  2. 将 A 的 ObjectFactory 放入三级缓存

    // 在 populateBean 之前执行
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, 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);}}
    }
    
  3. 属性注入 - 发现依赖 B

    // 在 populateBean 方法中
    for (BeanReference beanReference : beanReferences) {// 发现需要注入B,开始获取或创建BString refName = beanReference.getBeanName();Object refBean = getBean(refName);
    }
    

        2. 开始创建 B

  1. 实例化 B
  2. 将 B 的 ObjectFactory 放入三级缓存
  3. 属性注入 - 发现依赖 A

        3. B 获取 A 的流程

// B在属性注入时需要获取A
// 调用 getSingleton("a") 流程:// 1. 一级缓存:无A(A尚未创建完成)
// 2. 二级缓存:无A
// 3. 三级缓存:找到A的ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get("a");
if (singletonFactory != null) {// 通过ObjectFactory获取A的早期引用Object earlyReference = singletonFactory.getObject();// 将A从三级缓存移动到二级缓存this.earlySingletonObjects.put("a", earlyReference);this.singletonFactories.remove("a");return earlyReference;
}

        4. 完成创建过程

// B完成创建后,放入一级缓存
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}// A完成属性注入和初始化,放入一级缓存
// 此时B已经在一级缓存中,A可以直接注入完整的B

源码深度解析

    getEarlyBeanReference 方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能返回代理对象(如AOP)exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

    完整的 Bean 创建流程

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);Object bean = instanceWrapper.getWrappedInstance();// 2. 添加到三级缓存(解决循环依赖)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 属性注入(可能触发循环依赖)Object exposedObject = bean;populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);// 5. 处理循环依赖的早期引用if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}}return exposedObject;
}

特殊情况处理

    1. 构造器循环依赖(无法解决)

@Component
public class A {private B b;@Autowiredpublic A(B b) {  // 构造器注入this.b = b;}
}@Component
public class B {private A a;@Autowiredpublic B(A a) {  // 构造器注入this.a = a;}
}

原因:在构造器阶段就需要完整的依赖对象,而此时 Bean 还未实例化,无法放入三级缓存。

    2. 原型模式的循环依赖(无法解决)

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {@Autowiredprivate PrototypeB b;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {@Autowiredprivate PrototypeA a;
}

原因:原型模式不缓存 Bean 实例,每次都会创建新实例。

    3. 有 AOP 代理的情况

@Component
public class A {@Autowiredprivate B b;public void businessMethod() {// 业务方法}
}@Aspect
@Component
public class LogAspect {@Before("execution(* com.example.A.businessMethod(..))")public void logBefore() {System.out.println("方法执行前日志");}
}

处理流程

  1. 创建 A 的原始对象
  2. 将 A 的 ObjectFactory 放入三级缓存
  3. ObjectFactory 的 getEarlyBeanReference 方法会调用 AOP 相关的后处理器
  4. 返回 A 的代理对象作为早期引用

三级缓存总结

缓存级别存储内容作用生命周期
一级缓存完整的单例 Bean提供最终可用的 BeanBean 完全初始化后放入
二级缓存早期暴露的 Bean避免重复创建代理对象从三级缓存升级而来,最终移入一级缓存
三级缓存ObjectFactory创建早期引用,处理 AOPBean 实例化后放入,第一次获取后移除

设计思想

  1. 分离关注点:实例化、依赖注入、初始化分离
  2. 空间换时间:通过缓存提高性能
  3. 懒加载思想:ObjectFactory 延迟创建早期引用
  4. 代理兼容:支持 AOP 等增强功能

最佳实践

  1. 避免构造器循环依赖
  2. 优先使用 setter 注入
  3. 合理设计 Bean 依赖关系
  4. 了解缓存机制,优化性能

三级缓存机制是 Spring 框架解决循环依赖问题的精妙设计,理解其原理对于深入掌握 Spring IoC 容器至关重要。

















3️⃣ 参考 3

Spring 三级缓存原理详解

1. 三级缓存概述

Spring 的三级缓存是解决循环依赖问题的核心机制。所谓循环依赖,就是两个或多个 Bean 相互依赖,形成依赖闭环。

2. 三级缓存定义

DefaultSingletonBeanRegistry 类中定义了三级缓存:

public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例Bean(完全初始化好的Bean)private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例Bean(已实例化但未初始化的Bean)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的Bean名称集合private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

3. Bean 创建流程与三级缓存

    3.1 Bean 创建的基本流程

// 简化版的Bean创建流程
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(分配内存空间)Object bean = instanceWrapper.getWrappedInstance();// 2. 将Bean工厂放入三级缓存(解决循环依赖的关键)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 3. 属性注入(可能触发依赖Bean的创建)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化(调用初始化方法)exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}

4. 循环依赖解决过程

    4.1 场景:A 依赖 B,B 依赖 A

@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}

    4.2 详细解决流程

// 创建A的过程
1. getBean("A")→ 从一级缓存singletonObjects获取A,不存在→ 标记A为创建中:singletonsCurrentlyInCreation.add("A")→ 实例化A对象(此时A是个半成品,b=null2.AObjectFactory放入三级缓存addSingletonFactory("A", () -> getEarlyBeanReference("A", mbd, a))3. 属性注入:发现A依赖BgetBean("B")// 创建B的过程
4. getBean("B")→ 从一级缓存获取B,不存在→ 标记B为创建中:singletonsCurrentlyInCreation.add("B")→ 实例化B对象5.BObjectFactory放入三级缓存addSingletonFactory("B", () -> getEarlyBeanReference("B", mbd, b))6. 属性注入:发现B依赖AgetBean("A")7. 再次获取A→ 一级缓存:没有→ 二级缓存:没有→ 三级缓存:找到AObjectFactory→ 调用ObjectFactory.getObject()获取A的早期引用→ 将A从三级缓存移到二级缓存→ 返回A的早期引用给B8. B完成属性注入(此时B持有A的早期引用)
9. B完成初始化,放入一级缓存→ 从三级缓存移除BObjectFactory→ 从二级缓存移除B(如果有)→ singletonObjects.put("B", b)// 回到A的创建
10. A获得B的完整实例,完成属性注入
11. A完成初始化,放入一级缓存→ 从三级缓存移除AObjectFactory→ 从二级缓存移除A→ singletonObjects.put("A", a)

    4.3 缓存状态变化时序图

时间轴:      t1      t2      t3      t4      t5      t6
创建A:      开始实例化 → 放入三级缓存 → 属性注入需要B →              → 完成初始化
创建B:                     开始实例化 → 放入三级缓存 → 属性注入需要A → 完成初始化
三级缓存A:        空       有A工厂       有A工厂       空           空
二级缓存A:        空         空         空         有A早期引用     空
一级缓存A:        空         空         空         空           有A完整Bean

5. 源码关键方法解析

    5.1 getSingleton 方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存获取Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存获取singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存获取ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 创建早期引用singletonObject = singletonFactory.getObject();// 5. 移到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

    5.2 addSingletonFactory 方法

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 放入三级缓存this.singletonFactories.put(beanName, singletonFactory);// 清理二级缓存this.earlySingletonObjects.remove(beanName);}}
}

    5.3 getEarlyBeanReference 方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能返回代理对象(如AOP代理)exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

6. 特殊情况处理

    6.1 构造器循环依赖(无法解决)

@Component
public class A {private B b;@Autowiredpublic A(B b) {  // 构造器注入,无法解决循环依赖this.b = b;}
}@Component
public class B {private A a;@Autowiredpublic B(A a) {  // 构造器注入,无法解决循环依赖this.a = a;}
}

原因:在构造器注入时,Bean 还没有实例化,无法将 ObjectFactory 放入三级缓存。

    6.2 原型(Prototype)作用域的循环依赖(无法解决)

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {@Autowiredprivate PrototypeB b;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {@Autowiredprivate PrototypeA a;
}

原因:原型 Bean 不缓存,每次都会创建新实例。

7. 与 AOP 的协同工作

    7.1 代理对象的处理

@Component
public class ServiceA {@Autowiredprivate ServiceB serviceB;@Transactional  // 需要AOP代理public void method() {// ...}
}@Component  
public class ServiceB {@Autowiredprivate ServiceA serviceA;  // 这里注入的应该是代理对象
}

处理过程

  1. getEarlyBeanReference 方法中,AbstractAutoProxyCreator 会创建代理对象
  2. 三级缓存中存储的是能返回代理对象的 ObjectFactory
  3. 当发生循环依赖时,返回的是代理对象而不是原始对象

8. 总结

    8.1 三级缓存的作用

  • 一级缓存:存储完全初始化好的 Bean,可直接使用
  • 二级缓存:存储早期的 Bean 引用,用于避免重复创建代理对象
  • 三级缓存:存储 Bean 工厂,用于创建早期引用并处理 AOP 代理

    8.2 解决循环依赖的条件

  1. 必须是单例 Bean
  2. 不能是构造器注入(必须是字段注入或 setter 注入)
  3. 依赖的 Bean 必须能被提前暴露

    8.3 设计思想
Spring 的三级缓存机制体现了"空间换时间"和"关注点分离"的设计思想,通过缓存不同状态的 Bean 来优雅地解决复杂的循环依赖问题,同时保证了 Bean 创建过程的正确性和性能。

















4️⃣ 参考 4

Spring 三级缓存原理详解

1. 循环依赖问题

    1.1 什么是循环依赖

@Service
public class AService {@Autowiredprivate BService bService;
}@Service
public class BService {@Autowiredprivate AService aService;
}

这种相互依赖的情况就是循环依赖。

2. 三级缓存结构

Spring 通过三级缓存来解决循环依赖问题:

    2.1 三级缓存定义

public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象(尚未填充属性)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂缓存private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 正在创建中的 Beanprivate final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}

3. Bean 创建流程与三级缓存

    3.1 Bean 创建的主要步骤

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化Object bean = instanceWrapper.getWrappedInstance();// 2. 添加到三级缓存(解决循环依赖的关键)if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 属性填充(可能触发依赖 Bean 的创建)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}

    3.2 三级缓存的具体作用

        一级缓存:singletonObjects

  • 作用:存放完全初始化好的单例 Bean
  • 时机:Bean 完成所有初始化后放入

        二级缓存:earlySingletonObjects

  • 作用:存放早期的 Bean 引用(已实例化但未完成属性注入)
  • 时机:从三级缓存中获取到 Bean 后升级到此缓存

        三级缓存:singletonFactories

  • 作用:存放 Bean 的 ObjectFactory,用于创建早期引用
  • 时机:Bean 实例化后立即放入

4. 循环依赖解决流程

    4.1 AService 和 BService 的创建过程

// 创建 AService 的流程
1. beforeSingletonCreation("aService")  // 标记 aService 正在创建
2. instance = createBeanInstance()      // 实例化 AService 对象
3. addSingletonFactory("aService", () -> getEarlyBeanReference(...)) // 加入三级缓存// 此时三级缓存状态:
// singletonFactories: {"aService": ObjectFactory}4. populateBean("aService")             // 开始属性注入
5. 发现需要 bService,调用 getBean("bService")// 创建 BService 的流程  
6. beforeSingletonCreation("bService")  // 标记 bService 正在创建
7. instance = createBeanInstance()      // 实例化 BService 对象
8. addSingletonFactory("bService", () -> getEarlyBeanReference(...)) // 加入三级缓存9. populateBean("bService")             // 开始属性注入
10. 发现需要 aService,调用 getBean("aService")// 关键步骤:获取 aService
11. getSingleton("aService") 调用过程:- 一级缓存:没有找到 ✓- 二级缓存:没有找到 ✓  - 三级缓存:找到 ObjectFactory- 调用 ObjectFactory.getObject() 获取早期引用- 将 aService 从三级缓存升级到二级缓存- 返回 aService 的早期引用// 继续 BService 的创建
12. 将 aService 的早期引用注入到 BService
13. BService 完成初始化,放入一级缓存// 继续 AService 的创建  
14. 将完整的 BService 注入到 AService
15. AService 完成初始化,放入一级缓存

    4.2 源码中的关键方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存查找singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存查找ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 调用工厂方法获取早期引用singletonObject = singletonFactory.getObject();// 升级到二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

5. 为什么需要三级缓存?

    5.1 代理对象的处理
三级缓存主要为了解决 AOP 代理对象的循环依赖问题。

// ObjectFactory 的实现
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 这里可能会返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

    5.2 两级缓存的问题
如果只有两级缓存,会出现的问题:

  • 无法正确处理代理对象的循环依赖
  • 可能产生多个不同的代理对象实例

6. 特殊情况处理

    6.1 构造器循环依赖(无法解决)

@Service
public class AService {private final BService bService;@Autowiredpublic AService(BService bService) {this.bService = bService;}
}@Service  
public class BService {private final AService aService;@Autowiredpublic BService(AService aService) {this.aService = aService;}
}

结果:Spring 会抛出 BeanCurrentlyInCreationException

    6.2 原型模式的循环依赖

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class AService {@Autowiredprivate BService bService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
@Service
public class BService {@Autowiredprivate AService aService;
}

结果:Spring 会抛出 BeanCurrentlyInCreationException

7. 源码调试示例

    7.1 调试关键点

// 断点设置位置:
1. DefaultSingletonBeanRegistry.getSingleton()
2. AbstractAutowireCapableBeanFactory.doCreateBean()
3. AbstractAutowireCapableBeanFactory.createBeanInstance()
4. AbstractAutowireCapableBeanFactory.populateBean()// 观察三级缓存的变化:
- singletonObjects: 一级缓存
- earlySingletonObjects: 二级缓存  
- singletonFactories: 三级缓存
- singletonsCurrentlyInCreation: 正在创建的 Bean

8. 总结

    8.1 三级缓存的核心价值

  1. 解决循环依赖:通过提前暴露对象引用
  2. 保证单例:确保整个过程中只有一个 Bean 实例
  3. 支持 AOP:正确处理代理对象的循环依赖

    8.2 使用建议

  1. 避免构造器循环依赖:使用 @Autowired 字段注入或 setter 注入
  2. 理解作用域限制:只有单例 Bean 能解决循环依赖
  3. 合理设计架构:尽量减少循环依赖,提高代码可维护性

    8.3 核心流程图

Bean 实例化 → 加入三级缓存 → 属性注入 → 遇到依赖↓
依赖 Bean 创建 → 需要原始 Bean → 从三级缓存获取↓  
ObjectFactory.getObject() → 可能返回代理对象 → 升级到二级缓存↓
依赖 Bean 完成创建 → 原始 Bean 继续初始化 → 升级到一级缓存

通过三级缓存机制,Spring 优雅地解决了单例 Bean 的循环依赖问题,同时保证了 Bean 创建过程的正确性和一致性。

















5️⃣ 参考 5

Spring的三级缓存是Spring框架为解决单例Bean循环依赖问题而设计的核心机制,通过分阶段缓存Bean实例的不同状态,确保在依赖注入过程中避免重复创建和死循环。以下是其原理的详细说明:

    一、三级缓存的组成
Spring的三级缓存由三个Map结构组成,分别存储Bean在不同生命周期阶段的状态:

  1. 一级缓存(SingletonObjects)

    • 作用:存储已完全初始化好的单例Bean。
    • 特点:Bean已完成所有依赖注入和初始化(如@Autowired@PostConstruct等),可直接供其他Bean使用。
    • 数据结构ConcurrentHashMap<String, Object>,线程安全。
  2. 二级缓存(EarlySingletonObjects)

    • 作用:存储已实例化但未完全初始化的Bean(半成品Bean)。
    • 特点:Bean已完成实例化(如通过构造器或工厂方法创建),但尚未完成属性注入和初始化。
    • 使用场景:当Bean存在循环依赖时,提前暴露半成品Bean供其他Bean引用。
    • 数据结构HashMap<String, Object>,非线程安全(因一级缓存已保证线程安全)。
  3. 三级缓存(SingletonFactories)

    • 作用:存储Bean的工厂对象(ObjectFactory),用于动态生成代理对象或原始对象。
    • 特点
      • 解决AOP代理问题:若Bean需要被代理(如@Transactional@Async等),工厂对象可按需生成代理对象或原始对象。
      • 避免重复创建:通过Lambda表达式延迟对象生成,确保单例Bean的唯一性。
    • 数据结构HashMap<String, ObjectFactory<?>>,存储工厂接口。

    二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:

  1. 创建Bean A

    • Spring从一级缓存查找Bean A,未找到。
    • 创建Bean A的实例(调用构造器),并将其放入三级缓存(存储工厂对象)。
    • 开始属性注入,发现依赖Bean B。
  2. 创建Bean B

    • Spring从一级缓存查找Bean B,未找到。
    • 创建Bean B的实例,并将其放入三级缓存。
    • 开始属性注入,发现依赖Bean A。
  3. 解决Bean A的循环依赖

    • Spring从一级缓存查找Bean A,未找到;从二级缓存查找,未找到。
    • 从三级缓存获取Bean A的工厂对象,调用getObject()生成半成品Bean A(可能是代理对象)。
    • 将半成品Bean A放入二级缓存,并从三级缓存移除。
    • 将半成品Bean A注入Bean B。
  4. 完成Bean B的初始化

    • Bean B完成属性注入和初始化(如调用init-method)。
    • 将完全初始化的Bean B放入一级缓存,并从二级缓存移除。
  5. 完成Bean A的初始化

    • Spring继续Bean A的属性注入,从一级缓存获取完全初始化的Bean B。
    • Bean A完成初始化,放入一级缓存,并从二级缓存移除。

    三、三级缓存的核心作用

  1. 解决循环依赖

    • 通过提前暴露半成品Bean,打破循环依赖的死锁。
    • 例如:Bean A依赖Bean B,Bean B依赖Bean A时,三级缓存确保Bean A的半成品可被Bean B引用。
  2. 支持AOP代理

    • 三级缓存的工厂对象可按需生成代理对象,避免代理对象与原始对象冲突。
    • 例如:若Bean A需要被代理,工厂对象会返回代理对象而非原始对象。
  3. 保证单例唯一性

    • 通过一级缓存确保每个Bean仅初始化一次,避免重复创建。
  4. 提升性能

    • 缓存半成品Bean减少重复实例化开销,加速Bean创建过程。

    四、源码解析
关键方法位于DefaultSingletonBeanRegistry类中:

  1. getSingleton(String beanName, boolean allowEarlyReference)

    • 按一级缓存→二级缓存→三级缓存的顺序查找Bean。
    • 若从三级缓存获取,则调用工厂对象生成Bean,并升级到二级缓存。
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
    }
    
  2. addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)

    • 将Bean的工厂对象存入三级缓存,用于后续循环依赖处理。

    五、限制与注意事项

  1. 仅支持单例Bean

    • 多例(Prototype)Bean无法通过三级缓存解决循环依赖,因每次请求都会创建新实例。
  2. 构造器注入的局限性

    • 若循环依赖通过构造器注入(如public A(B b) {}),三级缓存无法解决,会抛出BeanCurrentlyInCreationException
    • 解决方案:改用Setter注入或字段注入。
  3. AOP代理的兼容性

    • 若Bean未被代理,三级缓存可简化为二级缓存(直接存储半成品Bean)。
    • 但为统一处理代理场景,Spring始终使用三级缓存。

















6️⃣ 参考 6

Spring三级缓存原理详解

Spring三级缓存是Spring框架解决Bean循环依赖问题的核心机制,通过"提前暴露半成品Bean"的方式,确保即使存在循环依赖也能正确初始化Bean。

三级缓存结构

  1. 一级缓存 (singletonObjects)

    • 存储完全初始化后的单例Bean
    • ConcurrentHashMap实现,Key为beanName
    • 是最终可以被使用的Bean实例
  2. 二级缓存 (earlySingletonObjects)

    • 存储已实例化但未初始化的"早期引用"
    • HashMap实现
    • 用于解决AOP代理问题
  3. 三级缓存 (singletonFactories)

    • 存储ObjectFactory函数式接口
    • 通过getObject()方法生成代理对象
    • 用于在Bean创建过程中提前暴露未完成的Bean

工作流程

当Spring容器需要获取一个Bean时,会按照以下顺序查询缓存:

先查一级缓存 → 无
查二级缓存 → 无
查三级缓存 → 执行ObjectFactory

循环依赖解决示例

以A依赖B,B依赖A的循环依赖为例:

  1. Spring先实例化A(A是半成品,属性未注入)
  2. 为A创建ObjectFactory,并放入三级缓存
  3. A需要注入B,开始实例化B
  4. B需要注入A,此时在三级缓存中找到A的ObjectFactory
  5. 通过ObjectFactory获取A的半成品对象
  6. B完成初始化,放入一级缓存
  7. A继续完成初始化,放入一级缓存

重要特性与限制

  1. 适用范围

    • 仅适用于Singleton作用域的Bean
    • 无法解决构造器注入的循环依赖(会抛出BeanCurrentlyInCreationException异常)
  2. AOP代理处理

    • 在getEarlyBeanReference方法中,如果有AOP配置,会在此生成代理对象
  3. 多线程问题

    • 三级缓存机制在多线程环境下仍可能出现NPE问题

为什么需要三级缓存?

  • 如果只用两级缓存(一级和二级),在AOP场景下会导致问题
  • 三级缓存提供了一个"工厂",可以在需要时生成代理对象,避免了在二级缓存中存储代理对象的问题

三级缓存的意义

通过三级缓存机制,Spring实现了:

  • 提前暴露未完成的Bean
  • 解决循环依赖问题
  • 保证Bean创建过程的一致性和正确性
  • 提高Bean实例的创建效率,避免重复创建

常见误区

  • 三级缓存不是为了解决所有循环依赖问题,而是解决Setter注入方式的循环依赖
  • 构造器注入的循环依赖无法通过三级缓存解决
  • 原型Bean的循环依赖问题无法通过三级缓存解决

理解Spring三级缓存原理对深入掌握IoC容器工作原理至关重要,也是Java开发者必须掌握的核心知识点之一。

















7️⃣ 参考 7

在Spring中,三级缓存是解决单例Bean循环依赖问题的核心机制。循环依赖指多个Bean之间互相依赖(如A依赖B,B依赖A),若不特殊处理,会导致Bean创建时陷入无限循环。三级缓存通过分层缓存设计,实现了Bean的“提前暴露”,从而打破循环依赖。

    一、三级缓存的定义
Spring通过三个缓存(Map结构)存储单例Bean的不同状态,按“完成度”从高到低分为:

  1. 一级缓存(singletonObjects)
    类型:Map<String, Object>
    作用:存储完全初始化完成的单例Bean(已实例化、属性注入、初始化方法执行完毕)。这是最终供用户使用的Bean。

  2. 二级缓存(earlySingletonObjects)
    类型:Map<String, Object>
    作用:存储提前暴露的早期Bean实例(已实例化,但未完成属性注入和初始化)。这些实例可能是原始对象,也可能是经过AOP代理的对象(若Bean需要被代理)。

  3. 三级缓存(singletonFactories)
    类型:Map<String, ObjectFactory<?>>
    作用:存储Bean的工厂对象(ObjectFactory)。工厂的作用是在需要时生成早期Bean实例(可能触发AOP代理创建),避免提前生成代理对象造成资源浪费。

    二、三级缓存的工作流程(以A依赖B,B依赖A为例)

  1. 创建Bean A的流程

    • 步骤1:Spring启动时,触发Bean A的创建,先检查一级缓存(singletonObjects),若不存在则继续。
    • 步骤2:实例化A(调用构造器生成原始对象),此时A尚未完成属性注入和初始化。
    • 步骤3:将A的工厂对象(ObjectFactory)放入三级缓存(singletonFactories)。工厂的逻辑是:若A需要AOP代理,则生成代理对象;否则返回原始对象。
    • 步骤4:开始为A注入属性,发现依赖B,此时触发Bean B的创建。
  2. 创建Bean B的流程

    • 步骤1:检查一级缓存,B不存在,继续创建。
    • 步骤2:实例化B,将B的工厂放入三级缓存。
    • 步骤3:为B注入属性,发现依赖A,开始查找A。
  3. 解决B对A的依赖

    • 步骤1:查找A时,先查一级缓存(A未完成,无),再查二级缓存(无),最后查三级缓存(存在A的工厂)。
    • 步骤2:通过A的工厂生成A的早期实例(若A需要代理,则此处生成代理对象),并将该实例从三级缓存移至二级缓存(earlySingletonObjects)。
    • 步骤3:将A的早期实例注入B,B完成属性注入和初始化,放入一级缓存(singletonObjects)。
  4. 完成A的创建

    • B创建完成后,回到A的属性注入步骤,将B从一级缓存中取出并注入A。
    • A完成属性注入和初始化,放入一级缓存(singletonObjects),同时从二级缓存中移除A的早期实例。

    三、为什么需要三级缓存?
核心原因是处理AOP代理场景下的循环依赖

  • 若仅用两级缓存(一级+二级),提前暴露的Bean只能是原始对象。但如果Bean需要AOP代理(如被@Transactional注解),最终应使用代理对象,而原始对象注入后会导致不一致(注入的是原始对象,最终容器中是代理对象)。
  • 三级缓存的工厂(ObjectFactory)实现了“延迟生成代理”:只有当循环依赖发生时,才会通过工厂生成代理对象并放入二级缓存,避免了无循环依赖时不必要的代理创建,同时保证注入的是正确的代理对象。

    四、适用范围与限制

  1. 仅支持单例Bean:原型Bean(scope="prototype")每次创建都是新实例,无法缓存,因此循环依赖会直接报错。
  2. 不支持构造器循环依赖:若A的构造器依赖B,B的构造器依赖A,由于实例化(构造器调用)前无法生成工厂对象,三级缓存无法生效,会报错。
  3. 依赖必须通过setter注入或字段注入:只有实例化后(构造器执行完),才能通过工厂提前暴露Bean,因此构造器注入无法解决循环依赖。

总结:三级缓存通过“提前暴露工厂→按需生成早期实例→最终完善Bean”的流程,既解决了单例Bean的循环依赖问题,又兼顾了AOP代理的正确性,是Spring容器设计的精妙之处。

















8️⃣ 参考 8

     Spring三级缓存原理详解

Spring的三级缓存机制是解决单例Bean循环依赖的核心设计,其工作原理如下:

         1. 三级缓存的定义

// Spring容器中的三级缓存
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存:完整Bean
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 二级缓存:半成品Bean
Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(); // 三级缓存:Bean工厂

         2. 解决循环依赖的流程(以A→B→A为例)

  1. 创建A实例

    • 实例化A(调用构造函数),此时A是原始对象
    • 将A的ObjectFactory存入三级缓存:singletonFactories.put("a", () -> getEarlyBeanReference(a))
  2. 填充A的属性

    • 发现A依赖B,触发B的创建
    • 此时A仍处于半成品状态(未完成属性注入)
  3. 创建B实例

    • 实例化B,将B的ObjectFactory存入三级缓存
    • 填充B属性时发现依赖A
  4. 解决依赖闭环

    • B从三级缓存获取A的ObjectFactory
    • 执行getEarlyBeanReference()生成A的早期引用(可能是代理对象)
    • 将A从三级缓存移除,存入二级缓存:earlySingletonObjects.put("a", proxyA)
  5. 完成初始化

    • B获得A的代理对象,完成属性注入→B初始化完成→存入一级缓存
    • A获得B的完整实例,完成属性注入→A初始化完成→存入一级缓存
创建A实例
存入三级缓存
填充属性需B
创建B实例
填充属性需A
从三级缓存取A工厂
生成A代理存入二级缓存
B完成初始化
A完成初始化

         3. 三级缓存的核心作用

缓存级别存储内容核心目的
一级缓存完整Bean(singletonObjects提供最终可用的Bean
二级缓存半成品Bean(earlySingletonObjects暂存早期暴露的对象
三级缓存Bean工厂ObjectFactory动态创建代理对象

关键设计亮点:

  • 三级缓存通过ObjectFactory实现延迟处理,在需要注入时才执行AOP代理逻辑
  • 避免直接暴露原始对象,确保注入的是最终代理对象(如@Transactional生效)

         4. 应用限制

依赖类型是否支持原因
Setter/字段注入✅ 支持可提前暴露半成品Bean
构造器注入❌ 不支持实例化前无法暴露引用
原型(Prototype)Bean❌ 不支持Spring不缓存原型Bean

         5. 典型案例分析
场景:AService需注入BService,BService需注入AService(二者都有@Async代理)
解决

  1. AService实例化后,存入三级缓存(含生成代理的ObjectFactory
  2. BService创建时通过ObjectFactory.getObject()获取A的代理对象
  3. 避免直接注入原始对象导致AOP失效

三级缓存的本质是:通过函数式编程分离实例化与代理过程,打破循环依赖的死锁

















9️⃣ 参考 9

Spring的三级缓存机制是其解决单例Bean循环依赖问题的核心设计,主要通过分层缓存提前暴露不完全初始化的Bean来实现。下面用一个表格帮你快速梳理这三级缓存:

缓存层级名称存储内容主要作用
一级缓存singletonObjects完全初始化完成的单例Bean提供最终可用的Bean,是正式的“单例池”
二级缓存earlySingletonObjects早期暴露的Bean(已实例化,但未完成初始化)解决循环依赖,避免多次从工厂创建实例
三级缓存singletonFactories创建Bean的工厂对象 (ObjectFactory)用于延迟创建早期引用,支持AOP代理

     🔧 三级缓存如何解决循环依赖

我们以经典的循环依赖为例:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A。

三级缓存有
创建Bean A
getBean(a)
实例化A
(调用构造函数)
得到A的原始对象
提前暴露A的引用
将 ObjectFactory 放入三级缓存
属性注入:A 依赖 B
触发 getBean(b)
创建Bean B
getBean(b)
实例化B
(调用构造函数)
得到B的原始对象
提前暴露B的引用
将 ObjectFactory 放入三级缓存
属性注入:B 依赖 A
触发 getBean(a)
再次查找A
一级缓存? --> 无
二级缓存? --> 无
通过ObjectFactory
获取A的早期引用
将A的早期引用放入二级缓存
并从三级缓存移除工厂
B注入A的早期引用成功
B完成初始化
放入一级缓存
回到A的属性注入流程
此时成功获取到完整的B
A完成初始化
将A放入一级缓存
并清理二、三级缓存
容器中存在
完全初始化的A和B

     ⚙️ 为何需要三级缓存?

你可能会问,为什么不能只用二级缓存?关键在于 AOP代理

如果只有二级缓存(直接存储对象),那么每次依赖注入时,注入的都将是原始的Bean对象。但如果这个Bean最终需要被AOP代理,那么就会出现问题:依赖注入的是原始对象,而正式使用的却是代理对象,这显然是不一致的。

三级缓存通过存入一个ObjectFactory工厂来解决这个问题。这个工厂(通常通过getEarlyBeanReference方法)能够在被调用时,智能地判断是否需要返回代理对象,从而保证最终注入的早期引用与最终完成的Bean(可能是代理对象)是同一个对象

     ⚠️ 注意事项

Spring的三级缓存机制很强大,但也有其局限性:

  1. 仅适用于单例Bean:原型(prototype)作用域的Bean无法使用三级缓存解决循环依赖。
  2. 不支持构造器循环依赖:如果循环依赖是通过构造器注入(Constructor Injection)方式发生的,三级缓存也无法解决。因为Spring必须通过构造器创建对象实例,在实例化之前无法提前暴露引用,会直接抛出BeanCurrentlyInCreationException异常。
  3. 设计警示:虽然Spring提供了这个机制,但从设计角度来说,应用程序中出现循环依赖通常是不推荐的,它可能意味着代码结构设计存在问题。

     💎 总结

简单来说,Spring的三级缓存是一个精巧的“缓兵之计”。它通过在Bean完全成型前就提供一个“预览版”(通过三级缓存工厂生成,可能是代理对象),让依赖它的其他Bean能继续组装下去,最终等所有Bean都组装完成后,再用“正式版”替换。

希望以上解释能帮助你理解Spring的三级缓存原理。

















🔟 参考 10

Spring 的三级缓存机制是其解决单例 Bean 循环依赖问题的核心设计,尤其在处理 AOP 代理场景时至关重要。以下从原理、实现和设计意图三个维度详细解析:


     一、三级缓存的结构与作用
Spring 的三级缓存定义在 DefaultSingletonBeanRegistry 类中,具体层级及功能如下:

缓存层级名称存储内容核心作用
一级缓存singletonObjects完全初始化的单例 Bean(包括依赖注入和 AOP 代理完成后的最终实例)直接提供可用的最终 Bean,供外部获取
二级缓存earlySingletonObjects实例化但未完成初始化的 Bean(如构造函数执行完成,但属性注入或初始化方法未执行)允许其他 Bean 在循环依赖中获取早期引用,打破循环等待
三级缓存singletonFactories存储生成早期引用的 ObjectFactory 对象支持动态生成代理对象(如 AOP 场景),确保不同依赖链获取的代理对象引用一致

     二、三级缓存解决循环依赖的流程(以 A → B → A 为例)

  1. 创建 Bean A

    • 实例化 A:调用构造函数生成原始对象。
    • 暴露早期引用:将 ObjectFactory 存入三级缓存(singletonFactories),用于后续生成早期引用(可能是代理对象)。
    • 依赖注入 B:发现 A 依赖 B,触发 B 的创建流程。
  2. 创建 Bean B

    • 实例化 B:生成原始对象。
    • 暴露早期引用:将 B 的 ObjectFactory 存入三级缓存。
    • 依赖注入 A:发现 B 依赖 A,尝试从缓存获取 A 的实例。
  3. 解决循环依赖

    • 从三级缓存获取 A 的工厂:调用 getObject() 生成 A 的早期引用(可能为代理对象)。
    • 存入二级缓存:将 A 的早期引用移至 earlySingletonObjects,供 B 注入。
    • 完成 B 的初始化:注入 A 的早期引用后,B 完成初始化并存入一级缓存。
  4. 完成 A 的初始化

    • 注入 B 的最终实例:从一级缓存获取已完成的 B,完成 A 的依赖注入。
    • A 存入一级缓存:A 的初始化完成后,移出二级缓存,最终存入一级缓存。

     三、三级缓存设计的核心意图

  1. 解决循环依赖

    • 通过提前暴露未完全初始化的 Bean(二级缓存),允许依赖链中的其他 Bean 获取引用,避免死锁。
  2. 支持 AOP 代理

    • 三级缓存存储 ObjectFactory,在生成早期引用时调用 getEarlyBeanReference(),确保代理对象的一致性。例如,若 A 被代理,B 注入的始终是同一代理实例。
  3. 并发控制与性能优化

    • 双重检查锁:在 getSingleton() 方法中,首次创建 Bean 时加锁,后续直接读取缓存,减少锁竞争。
    • 延迟初始化:三级缓存通过工厂模式延迟生成早期引用,避免不必要的对象创建。

     四、关键代码逻辑(简化版)

// AbstractAutowireCapableBeanFactory#doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化 BeanObject bean = createBeanInstance(beanName, mbd, args);// 2. 提前暴露工厂到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 3. 填充属性(依赖注入)populateBean(beanName, mbd, bean);// 4. 初始化 Bean(完成 AOP 代理等)initializeBean(beanName, bean, mbd);// 5. 移除三级缓存,存入一级缓存addSingleton(beanName, bean);return bean;
}// 获取早期引用的工厂方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {// 若存在 AOP 代理,返回代理对象return (mbd == null || !mbd.isSynthetic()) ? bean : wrapIfNecessary(beanName, bean, mbd);
}

     五、常见问题与误区

  • 为什么需要三级而非两级缓存?
    二级缓存仅能存储原始对象,无法处理 AOP 代理场景。三级缓存通过工厂模式动态生成代理,确保引用一致性。

  • 循环依赖是否设计缺陷?
    Spring 官方认为循环依赖是设计问题,但实际开发中难以完全避免(如复杂业务场景)。三级缓存是权衡后的解决方案。

  • 并发下的线程安全
    通过 ConcurrentHashMap 和双重检查锁(synchronized + volatile)保证多线程环境下缓存的正确性。


     总结
Spring 的三级缓存通过分层存储 Bean 的不同生命周期状态,巧妙解决了循环依赖和 AOP 代理的兼容性问题。其设计体现了对性能、灵活性和线程安全的综合考量,是 Spring IoC 容器的核心机制之一。

















🤔 参考 11

我们来详细、系统地解析一下 Spring 框架中三级缓存(3-level Cache) 的原理。这是一个理解 Spring 如何解决循环依赖(Circular Dependency) 问题的核心概念。

     一句话概括

Spring 的三级缓存是为了解决单例(Singleton)Bean 的循环依赖问题,同时保证在处理循环依赖时,注入的代理对象(如 AOP 创建的代理)是同一个对象而设计的一套机制。


     1. 什么是循环依赖?

循环依赖是指两个或以上的 Bean 相互持有对方,构成了一个循环引用链。例如:

  • Bean A 的构造函数需要 Bean B 作为参数。
  • Bean B 的构造函数需要 Bean A 作为参数。

Spring 默认支持基于 Setter 注入或字段注入的循环依赖,但不支持基于构造器注入的循环依赖。三级缓存主要解决的是前两种情况。


     2. 三级缓存分别是什么?

在 Spring 的 DefaultSingletonBeanRegistry 类中,定义了三个非常重要的 Map,也就是我们常说的“三级缓存”:

  1. 一级缓存:singletonObjects

    • 类型: ConcurrentHashMap<String, Object>
    • 存放内容: 存放已经完全初始化好的、成熟的单例 Bean
    • 作用: 这是最主要的缓存。我们通过 ApplicationContext.getBean() 方法最终获取到的就是这里的 Bean。
  2. 二级缓存:earlySingletonObjects

    • 类型: HashMap<String, Object>
    • 存放内容: 存放早期的、未完全初始化的 Bean 实例(已经实例化,但属性还未填充)。
    • 作用: 它是一级缓存的临时替补。当一个早期对象被其他 Bean 依赖过后,就会被放在这里,避免再次创建代理对象的开销。
  3. 三级缓存:singletonFactories

    • 类型: HashMap<String, ObjectFactory<?>>
    • 存放内容: 存放的是Bean 工厂对象(ObjectFactory),而不是 Bean 实例本身。这个工厂可以返回一个目标 Bean 的早期引用(可能是原始对象,也可能是代理对象)。
    • 作用: 这是解决循环依赖和 AOP 代理问题的关键。它通过一个工厂来延迟决定最终返回的对象,从而能够智能地处理是否需要提前创建 AOP 代理。

     3. 解决循环依赖的完整流程(核心)

让我们以两个 Bean:A 和 B 相互依赖为例(A 中有 B,B 中有 A)。

  1. 开始创建 A

    • Spring 调用 A 的构造器,实例化一个“原始对象”。
    • 随后,Spring 将创建 A 的 ObjectFactory 工厂对象,并放入三级缓存 (singletonFactories) 中。
  2. 为 A 填充属性(Populate)

    • Spring 发现 A 依赖 B,于是尝试去获取 Bean B。
  3. 开始创建 B

    • Spring 调用 B 的构造器,实例化一个“原始对象”。
    • 随后,Spring 将创建 B 的 ObjectFactory 工厂对象,并放入三级缓存 (singletonFactories) 中。
  4. 为 B 填充属性(Populate)

    • Spring 发现 B 依赖 A,于是尝试去获取 Bean A。
  5. 获取 A(关键步骤!)

    • Spring 首先去一级缓存 (singletonObjects) 找 A,没有找到(A 还没创建完)。
    • 然后去二级缓存 (earlySingletonObjects) 找 A,也没有找到(A 还没被依赖过)。
    • 最后去三级缓存 (singletonFactories) 找,成功找到了 A 的 ObjectFactory
    • 调用 ObjectFactory.getObject() 方法。
      • 如果 A 是一个普通 Bean,这个方法直接返回 A 的原始对象。
      • 如果 A 需要被 AOP 代理,这个方法会提前触发 AOP 逻辑,生成一个代理对象并返回。
    • 将这个从三级缓存中得到的对象(可能是原始对象,也可能是代理对象)放入二级缓存 (earlySingletonObjects) 中,同时从三级缓存中移除对应的 ObjectFactory
    • 最后,将这个早期引用注入给 Bean B
  6. 完成 B 的创建

    • B 注入 A 成功后,继续完成 B 的其他生命周期步骤(初始化等)。
    • B 创建完毕,被放入一级缓存 (singletonObjects),并从二、三级缓存中清除。
  7. 回到 A 的创建

    • 此时 Bean B 已经创建好,成功注入到 A 中。
    • A 继续完成它的属性填充和初始化步骤。
    • A 创建完毕,被放入一级缓存 (singletonObjects),并从二、三级缓存中清除。

至此,循环依赖成功解决,A 和 B 都完成了创建。


     4. 为什么需要三级缓存?两级不行吗?

这是一个非常经典的面试题。答案是:为了处理 AOP 代理,两级缓存理论上可以,但会有重复创建代理的风险,性能更差,而三级缓存的设计非常精妙地避免了这一点。

  • 如果没有三级缓存(singletonFactories),只有一级和二级缓存:

    • 在上述第 5 步,我们无法通过一个工厂来“智能地”判断是否需要创建代理。
    • 我们只能选择:要么在实例化后立刻进行 AOP 代理,然后把这个代理对象直接放入二级缓存。
    • 问题: 如果这个 Bean 没有被循环依赖(即没有其他 Bean 提前引用它),那么它根本不需要提前生成代理。提前创建代理是不合理且浪费的,因为代理的最终生成可能还依赖于后续的初始化操作(如 @PostConstruct)。
    • 更大的问题: 如果多个 Bean 同时循环依赖它,这个提前创建的代理对象可能会被多次生成(因为每次依赖都要走一遍创建逻辑),违背了单例原则。
  • 三级缓存的作用:

    • 它通过一个 ObjectFactory延迟决策。只有在真正发生循环依赖,需要提前暴露引用时,才会调用工厂的 getObject() 方法。
    • 这个方法内部有逻辑保证:对于同一个 Bean,多次调用 getObject() 返回的都是同一个代理对象,确保了单例。
    • 如果没有发生循环依赖,这个工厂永远不会被调用,Bean 会按正常流程在初始化之后才创建代理,这样更加合理和高效。

简单比喻:

  • 二级缓存方案: 不管有没有客人来,先把菜做好放在备餐台(二级缓存)上。
  • 三级缓存方案: 先把食材准备好,并雇好一个厨师(ObjectFactory)。只有客人点这道菜时,厨师才立刻现场制作,并且保证所有客人吃到的都是同一份。

     总结

缓存级别名称(Map)内容目的
一级缓存singletonObjects完整的单例 Bean提供最终可用的 Bean
二级缓存earlySingletonObjects早期的 Bean 引用(可能是代理)避免重复创建早期引用,提升性能
三级缓存singletonFactories生成早期引用的工厂核心: 延迟化、智能化处理 AOP 代理,保证单例

核心思想: Spring 通过提前暴露对象实例(存入三级缓存)来解决循环依赖,并通过 ObjectFactory 的巧妙设计来统一处理普通 Bean 和代理 Bean 的创建过程,既解决了问题,又保证了性能和高扩展性。

















🤔 参考 12

Spring 的三级缓存机制是其解决 bean 循环依赖问题的关键设计,以下是对其原理及相关内容的详细介绍:

     一、三级缓存的结构与作用

  1. 一级缓存 singletonObjects

    • 功能: 存储已完全初始化并可用的单例 Bean 实例[1][2][4]。
    • 特点: 其中的 Bean 已完成所有属性注入和非惰性初始化操作,可直接返回给请求者使用[1][2][4]。
  2. 二级缓存 earlySingletonObjects

    • 功能: 存放早期暴露的 Bean 引用,这些对象已完成实例化但尚未完成属性注入或初始化[1][2][4]。
    • 作用: 允许其他 Bean 在创建过程中引用尚未完全初始化的 Bean,从而解决循环依赖问题[1][2][4]。
  3. 三级缓存 singletonFactories

    • 功能: 存储可生成 Bean 实例的工厂对象(ObjectFactory),而非直接存储 Bean 实例[1][2][4]。
    • 核心作用: 应对 AOP 代理场景。若 Bean 需要被代理(如通过 SmartInstantiationAwareBeanPostProcessor),则通过工厂动态生成代理对象而非原始对象[1][5]。

     二、三级缓存解决循环依赖的流程

  1. 首次创建 Bean A

    • Spring 实例化 Bean A 后,将其封装为 ObjectFactory 并存入三级缓存 singletonFactories[1][5]。此时暂不放入一/二级缓存。
  2. 处理 Bean A 的依赖 Bean B

    • 当尝试注入 Bean B 时,发现其尚未创建,于是开始创建 Bean B。同样地将Bean B的 ObjectFactory 存入三级缓存。
  3. 检测到循环依赖

    • 当创建 Bean B 的过程中试图注入 Bean A 时,从三级缓存中获取 Bean A 的 ObjectFactory,调用其 getObject() 方法生成早期引用[1][5]。
  4. 升级缓存层级

    • 将 Bean A 的早期引用从三级缓存移至二级缓存 earlySingletonObjects,供 Bean B 完成属性注入[1][5]。
  5. 完成初始化并最终放入一级缓存

    • Bean B 完成属性注入后,将其完整实例放入一级缓存 singletonObjects[1][5]。
    • 随后继续完成 Bean A 的初始化,最终也将 Bean A 放入一级缓存。

     三、为何需要三级缓存而非二级?

  1. 支持 AOP 代理:若仅用二级缓存(直接存储未初始化完成的 Bean),则无法区分是否需要代理。三级缓存通过 ObjectFactory 可在获取 Bean 时动态判断是否需要生成代理对象[1][5]。

  2. 延迟代理对象的创建:避免了在 Bean 生命周期早期错误地生成代理对象,确保 AOP 逻辑仅在必要时执行[1][5]。

  3. 线程安全与性能优化:三级缓存通过分层设计和同步块控制,减少了并发场景下的锁竞争,提升了性能[5]。

     四、关键前提条件

  1. 单例模式:循环依赖的两个 Bean 必须都是单例的[3][4]。

  2. 非构造函数注入:构造函数注入会导致实例化阶段陷入死循环,因为构造函数要求所有依赖立即可用[3][4]。

总的来说,Spring 的三级缓存通过分阶段存储 Bean 的不同状态(实例化 → 属性注入 → 初始化完成),结合工厂模式动态生成代理对象,巧妙解决了循环依赖问题。这一机制不仅保证了Bean生命周期的正确性,还兼容了 AOP 等高级特性,是 Spring IoC 容器的核心设计之一。

















🤔 参考 13

Spring 的三级缓存机制是 Spring 解决循环依赖问题的核心机制,主要应用于单例 Bean 的创建过程中。它由三个缓存(Map)组成,分别用于存储不同状态的 Bean 对象。以下是三级缓存的原理和作用:


     1. 三级缓存的组成

Spring 使用三个 Map 结构作为缓存,分别如下:

  • 一级缓存(singletonObjects)
    存放已经完全初始化好的单例 Bean(可以直接使用的 Bean)。

  • 二级缓存(earlySingletonObjects)
    存放提前暴露的“早期 Bean”(尚未完成属性注入和初始化)。

  • 三级缓存(singletonFactories)
    存放 Bean 工厂对象(ObjectFactory),用于创建早期 Bean 的代理对象(用于支持 AOP)。


     2. 三级缓存的工作流程

当 Spring 创建一个单例 Bean 时,会经历以下流程:

  1. 创建 Bean 实例(newInstance)

    • 调用构造方法创建一个原始对象(未注入属性、未初始化)。
  2. 将 Bean 工厂放入三级缓存中

    • 将一个 ObjectFactory 放入三级缓存 singletonFactories,用于后续获取代理对象。
  3. 填充属性(populateBean)

    • 如果依赖的其他 Bean 还未创建,会触发它们的创建流程,可能形成循环依赖。
  4. 提前暴露 Bean(放入二级缓存)

    • 从三级缓存中获取 Bean 工厂,创建代理对象(如果有 AOP 需要),并将其移动到二级缓存。
  5. 完成初始化(initializeBean)

    • 注入属性、调用初始化方法(如 init-method、@PostConstruct)。
  6. 将 Bean 放入一级缓存

    • 完全初始化好的 Bean 被放入一级缓存 singletonObjects,供其他 Bean 使用。

     3. 如何解决循环依赖?

以 A 依赖 B,B 又依赖 A 的情况为例:

  • 创建 A 时,A 被实例化后放入三级缓存。
  • A 填充属性时发现依赖 B,于是开始创建 B。
  • B 实例化后,填充属性时发现依赖 A,于是从 A 的三级缓存中获取早期的 A(可能是代理对象)。
  • B 创建完成后放入一级缓存,A 继续完成初始化。
  • 最终 A 和 B 都被正确创建,解决循环依赖。

     4. 注意事项

  • 只适用于单例作用域的 Bean
  • 不能解决构造器注入的循环依赖(因为构造器注入必须在实例化时完成依赖注入)。
  • 依赖的提前暴露是关键,三级缓存机制确保了即使对象未完全初始化,也能被其他对象引用。

     总结

Spring 的三级缓存机制通过提前暴露未完全初始化的 Bean,结合工厂模式和代理机制,巧妙地解决了单例 Bean 的循环依赖问题,是 Spring 容器设计中的经典实现。

















🤔 参考 14

Spring的三级缓存是Spring框架在管理Bean生命周期时采用的一种核心机制,主要用于解决循环依赖问题,同时优化Bean的创建效率。其原理通过三个不同层级的缓存(一级、二级、三级)存储Bean在不同生命周期阶段的状态,确保单例Bean的线程安全创建和高效复用。

    一、三级缓存的组成与作用

  1. 一级缓存(SingletonObjects)

    • 存储内容:完全初始化好的单例Bean。
    • 作用:Bean在完成所有初始化步骤(如依赖注入、初始化方法调用、AOP代理等)后,会被放入一级缓存。后续获取Bean时直接从此缓存返回,避免重复创建。
    • 特点:线程安全,使用ConcurrentHashMap实现,保证高并发下的正确性。
  2. 二级缓存(EarlySingletonObjects)

    • 存储内容:已实例化但未完全初始化的Bean(半成品Bean)。
    • 作用:在Bean初始化过程中,若其他Bean依赖它,Spring会先将半成品Bean放入二级缓存,供依赖方提前使用。
    • 特点:解决循环依赖的关键,允许Bean在未完全初始化时被引用,但避免重复创建。
  3. 三级缓存(SingletonFactories)

    • 存储内容:Bean的ObjectFactory对象(通常是一个Lambda表达式)。
    • 作用:当Bean需要被代理(如AOP场景)时,三级缓存存储的是生成代理对象的工厂。通过工厂可以动态决定返回原始Bean还是代理Bean,保证全局唯一性。
    • 特点:解决AOP代理与循环依赖的兼容问题,确保代理对象在循环依赖中也能正确生成。

    二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:

  1. 创建Bean A

    • Spring先检查一级缓存,未找到Bean A。
    • 创建Bean A的实例(未注入依赖),将其对应的ObjectFactory放入三级缓存。
    • 开始填充Bean A的属性,发现依赖Bean B。
  2. 创建Bean B

    • 检查一级缓存,未找到Bean B。
    • 创建Bean B的实例,将其ObjectFactory放入三级缓存。
    • 开始填充Bean B的属性,发现依赖Bean A。
  3. 解决Bean A的循环依赖

    • Spring从三级缓存获取Bean A的ObjectFactory,调用getObject()方法生成Bean A的早期引用(可能是代理对象)。
    • 将Bean A的早期引用从三级缓存移除,并放入二级缓存。
    • Bean B完成属性注入(使用二级缓存中的Bean A早期引用),继续初始化。
  4. 完成Bean B的初始化

    • Bean B完成所有初始化步骤后,被放入一级缓存。
    • 从二级缓存中移除Bean A的早期引用(若存在)。
  5. 完成Bean A的初始化

    • Spring继续初始化Bean A,使用一级缓存中的Bean B完成属性注入。
    • Bean A完成所有初始化步骤后,被放入一级缓存。

    三、三级缓存的核心优势

  1. 解决循环依赖
    通过提前暴露半成品Bean(二级缓存)和动态生成代理对象(三级缓存),避免循环依赖导致的无限递归或死锁。

  2. 优化性能

    • 减少重复创建:已初始化的Bean直接从一级缓存返回,避免重复实例化。
    • 懒加载支持:二级缓存实现Bean的按需初始化,降低启动时间。
  3. 兼容AOP代理
    三级缓存的ObjectFactory机制确保代理对象在循环依赖中也能正确生成,解决原始Bean与代理Bean的冲突问题。

  4. 线程安全保障
    一级缓存使用ConcurrentHashMap,二级和三级缓存通过同步块(synchronized)保证多线程环境下的正确性。

    四、三级缓存的适用场景

  • 单例Bean的循环依赖:仅对作用域为singleton的Bean有效,原型(prototype)Bean无法使用三级缓存。
  • AOP代理场景:当Bean需要被代理时,三级缓存的工厂机制确保代理对象在循环依赖中也能正确生成。
  • 高并发环境:通过缓存机制减少锁竞争,提升Bean创建效率。

    五、源码解析关键方法

  1. getSingleton(String beanName, boolean allowEarlyReference)

    • 核心逻辑:按一级→二级→三级缓存的顺序查找Bean。
    • 若在三级缓存找到,调用ObjectFactory.getObject()生成早期引用,移入二级缓存并删除三级缓存条目。
  2. addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)

    • 将Bean的ObjectFactory放入三级缓存,用于后续循环依赖的解决。
  3. doGetBean()createBean()

    • 控制Bean的创建流程,包括依赖注入、初始化、缓存操作等。

















🤔 参考 15

Spring的三级缓存机制是其解决循环依赖问题的核心设计,主要应用于单例(Singleton)Bean的创建过程中。这个机制通过三个Map(通常称为“三级缓存”)来实现,确保在复杂的依赖注入场景下,Bean能够被正确、高效地创建和初始化。

以下是三级缓存的具体原理和作用:

     1. 三级缓存的定义

Spring的DefaultSingletonBeanRegistry类中定义了三个Map,它们共同构成了三级缓存:

  • 一级缓存 (singletonObjects):

    • 类型: ConcurrentHashMap<String, Object>
    • 作用: 存放完全初始化好的单例Bean实例。这些Bean已经完成了实例化、属性填充(依赖注入)和初始化方法(如@PostConstructInitializingBean)的调用。
    • 特点: 这是最终的、可供使用的Bean仓库。当一个Bean被请求时,Spring会首先从此缓存中查找。
  • 二级缓存 (earlySingletonObjects):

    • 类型: ConcurrentHashMap<String, Object>
    • 作用: 存放提前暴露的、原始的Bean实例。这些实例已经通过构造函数创建(实例化完成),但尚未进行属性填充和初始化
    • 特点: 用于解决循环依赖。当一个Bean A在创建过程中依赖Bean B,而Bean B又依赖Bean A时,Spring会将Bean A的早期引用(一个未完全初始化的对象)放入此缓存,供Bean B注入使用。
  • 三级缓存 (singletonFactories):

    • 类型: ConcurrentHashMap<String, ObjectFactory<?>>
    • 作用: 存放能够创建早期Bean实例的工厂(ObjectFactory)。这个工厂通常是一个Lambda表达式,其核心是getEarlyBeanReference()方法。
    • 特点: 这是解决循环依赖和AOP代理的关键。它不直接存放对象,而是存放一个可以获取对象的“生产指令”。当需要早期引用时,会通过这个工厂来获取。

     2. 三级缓存的工作流程(以解决循环依赖为例)

假设存在循环依赖:AService 依赖 BService,而 BService 又依赖 AService

  1. 开始创建 AService:

    • Spring发现需要创建AService,首先检查一级缓存singletonObjects,没有找到。
    • 然后检查二级缓存earlySingletonObjects,也没有找到。
    • 接着检查三级缓存singletonFactories,同样没有。
    • 于是开始创建AService
  2. 暴露 AService 的早期引用:

    • AService通过构造函数实例化完成(此时AService对象已存在,但属性还未注入)。
    • Spring将一个ObjectFactory(工厂)放入三级缓存singletonFactories中。这个工厂的作用是:当被调用时,可以返回AService的早期引用。
    • 关键点: 此时AService的早期引用尚未真正创建,只是准备好了创建它的“方法”。
  3. 注入依赖 - 创建 BService:

    • AService需要注入BService,于是Spring开始创建BService
    • BService的创建流程类似,实例化完成后,也会将其ObjectFactory放入三级缓存。
    • BService需要注入AService
  4. 解决循环依赖 - 获取 AService 的早期引用:

    • 在为BService注入AService时,Spring再次查找AService
    • 一级、二级缓存都没有,但在三级缓存中找到了AServiceObjectFactory
    • Spring调用这个ObjectFactorygetObject()方法。
    • getObject()方法内部会调用getEarlyBeanReference()这一步至关重要
      • 如果AService需要被AOP代理(例如有@Transactional注解),那么getEarlyBeanReference()会在这里创建代理对象。
      • 如果不需要代理,则直接返回原始的AService实例。
    • 将得到的早期引用(可能是原始对象,也可能是代理对象)放入二级缓存earlySingletonObjects
    • 同时,从三级缓存中移除AServiceObjectFactory。这保证了早期引用只会被创建一次。
    • 将这个早期引用注入到BService中。
  5. 完成 BService 的创建:

    • BService完成属性填充和初始化,成为一个完整的Bean,放入一级缓存singletonObjects
    • 从二级和三级缓存中移除BService的相关条目。
  6. 完成 AService 的创建:

    • 回到AService的创建流程,此时BService已经创建完毕。
    • BService注入到AService中。
    • AService完成初始化,成为一个完整的Bean,放入一级缓存singletonObjects
    • 从二级和三级缓存中移除AService的相关条目。

     3. 为什么需要三级缓存?二级不够吗?

这是理解Spring设计精髓的关键。

  • 如果只有二级缓存:在AService实例化后,直接将其原始对象放入二级缓存。当BService需要AService时,从二级缓存获取并注入。

  • 问题在于AOP:如果AService是一个需要被代理的Bean(比如有@Transactional),那么最终放入一级缓存的应该是代理对象,而不是原始对象。但如果在早期就将原始对象暴露出去并被其他Bean持有,那么当AService最终创建完成时,生成的代理对象与之前注入的原始对象就不一致了,导致出现两个不同的实例,破坏了单例原则和AOP的预期行为。

  • 三级缓存的解决方案

    • 三级缓存不直接存放对象,而是存放一个工厂
    • 这个工厂(ObjectFactory)的getObject()方法会在被调用时,通过getEarlyBeanReference()动态决定返回的是原始对象还是代理对象。
    • 这样,无论是早期引用还是最终的完整Bean,都保证是同一个对象(要么都是原始对象,要么都是代理对象),从而保证了对象的一致性。

     总结

Spring的三级缓存是一个精巧的设计:

  • 一级缓存:存放最终的、完整的单例Bean。
  • 二级缓存:存放提前暴露的原始Bean实例(或代理),用于打破循环依赖。
  • 三级缓存:存放创建早期引用的工厂,核心作用是解决循环依赖与AOP代理之间的矛盾,确保无论何时获取的引用,最终指向的都是同一个最终对象(特别是代理对象)。

通过这三级缓存的协同工作,Spring能够在保证Bean生命周期完整性的前提下,高效地解决单例Bean之间的循环依赖问题。

















🤔 参考 16 Spring 如何解决循环依赖

Spring 如何解决循环依赖

1. 循环依赖的定义与类型

    1.1 什么是循环依赖

// 示例:两个 Bean 相互依赖
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowired private UserService userService;  // 循环依赖
}

    1.2 循环依赖的类型

  • 构造器循环依赖:无法解决
  • Setter/字段循环依赖:可以通过三级缓存解决
  • 原型 Bean 循环依赖:无法解决

2. 三级缓存机制

    2.1 三级缓存定义
DefaultSingletonBeanRegistry 中:

public class DefaultSingletonBeanRegistry {// 一级缓存:完整的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:早期的单例对象private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:单例工厂private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
}

    2.2 三级缓存的作用

缓存级别存储内容作用
一级缓存完全初始化好的 Bean提供最终的单例实例
二级缓存早期暴露的对象避免重复创建代理对象
三级缓存ObjectFactory 工厂支持 AOP 代理等后处理

3. 循环依赖解决流程

    3.1 核心解决算法

// 获取 Bean 的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存查找Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 2. 从二级缓存查找singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 3. 从三级缓存获取 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 4. 通过工厂创建早期引用singletonObject = singletonFactory.getObject();// 5. 放入二级缓存,从三级缓存移除this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}

    3.2 详细解决步骤

UserServiceOrderService 循环依赖为例:

// 步骤1:开始创建 UserService
1. beforeSingletonCreation("userService")  // 标记正在创建
2. instance = instantiateBean("userService")  // 实例化 UserService
3. addSingletonFactory("userService", () -> getEarlyBeanReference("userService", mbd, instance))  // 添加到三级缓存// 步骤2:填充 UserService 属性
4. populateBean("userService", mbd, instance)  // 发现需要 orderService
5. getBean("orderService")  // 开始创建 OrderService// 步骤3:开始创建 OrderService  
6. beforeSingletonCreation("orderService")  // 标记正在创建
7. instance = instantiateBean("orderService")  // 实例化 OrderService
8. addSingletonFactory("orderService", () -> getEarlyBeanReference("orderService", mbd, instance))  // 添加到三级缓存// 步骤4:填充 OrderService 属性
9. populateBean("orderService", mbd, instance)  // 发现需要 userService
10. getSingleton("userService")  // 获取 UserService- 一级缓存:无- 二级缓存:无- 三级缓存:找到 UserServiceObjectFactory- 调用 factory.getObject() 获取早期引用-UserService 移到二级缓存// 步骤5:完成 OrderService 创建
11. initializeBean("orderService")  // 初始化 OrderService
12. addSingleton("orderService", instance)  // 放入一级缓存// 步骤6:完成 UserService 创建
13. 回到 UserService 的属性填充,注入 OrderService
14. initializeBean("userService")  // 初始化 UserService  
15. addSingleton("userService", instance)  // 放入一级缓存

4. Bean 创建的关键时机点

    4.1 Bean 生命周期与缓存

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 1. 实例化(创建原始对象)Object beanInstance = instantiateBean(beanName, mbd);// 2. 暴露早期引用(关键步骤!)boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {// 添加到三级缓存 - 解决循环依赖的核心addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, beanInstance));}// 3. 属性填充(可能触发循环依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}

    4.2 三级缓存的添加

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);}}
}

5. AOP 代理的特殊处理

    5.1 代理对象的创建时机

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会创建并返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

    5.2 AOP 代理示例

@Service
public class UserService {@Autowiredprivate OrderService orderService;@Transactional  // 需要 AOP 代理public void updateUser() {// 事务方法}
}@Service  
public class OrderService {@Autowiredprivate UserService userService;  // 这里注入的应该是代理对象
}

处理流程

  1. UserService 实例化后,三级缓存中的 ObjectFactory 会检查是否需要 AOP 代理
  2. 由于有 @TransactionalgetEarlyBeanReference 返回代理对象
  3. OrderService 注入的是 UserService 的代理对象
  4. 保证事务功能正常工作

6. 无法解决的循环依赖情况

    6.1 构造器循环依赖

@Service
public class UserService {private final OrderService orderService;// 构造器注入 - 无法解决!public UserService(OrderService orderService) {this.orderService = orderService;}
}@Service
public class OrderService {private final UserService userService;public OrderService(UserService userService) {this.userService = userService;}
}

原因:Bean 还没有实例化,无法添加到三级缓存,Spring 会直接抛出 BeanCurrentlyInCreationException

    6.2 原型 Bean 循环依赖

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {@Autowiredprivate OrderService orderService;
}@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service  
public class OrderService {@Autowiredprivate UserService userService;
}

原因:原型 Bean 每次都会创建新实例,Spring 不支持原型 Bean 的循环依赖

7. 解决方案与最佳实践

    7.1 使用 @Lazy 注解

@Service
public class UserService {@Lazy  // 延迟注入,打破循环依赖@Autowiredprivate OrderService orderService;
}@Service
public class OrderService {@Autowiredprivate UserService userService;  // 正常注入
}

    7.2 使用 Setter 注入

@Service
public class UserService {private OrderService orderService;// Setter 注入@Autowiredpublic void setOrderService(OrderService orderService) {this.orderService = orderService;}
}

    7.3 使用 ApplicationContext

@Service
public class UserService implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}public void someMethod() {// 需要时再获取 OrderServiceOrderService orderService = applicationContext.getBean(OrderService.class);}
}

    7.4 代码重构

// 方案1:提取公共逻辑到第三个类
@Service
public class CommonService {// 公共逻辑
}@Service
public class UserService {@Autowiredprivate CommonService commonService;
}@Service
public class OrderService {@Autowiredprivate CommonService commonService;
}// 方案2:使用接口分离
public interface UserOperation {void userOperation();
}public interface OrderOperation {void orderOperation();  
}@Service
public class UserService implements UserOperation {@Autowiredprivate OrderOperation orderOperation;
}@Service
public class OrderService implements OrderOperation {@Autowiredprivate UserOperation userOperation;
}

8. 调试与问题排查

    8.1 启用循环依赖日志

##########  application.properties
logging.level.org.springframework.beans=DEBUG
logging.level.org.springframework.context=DEBUG

    8.2 自定义循环依赖检测

@Component
public class CircularDependencyChecker implements ApplicationRunner {@Autowiredprivate ConfigurableListableBeanFactory beanFactory;@Overridepublic void run(ApplicationArguments args) {detectCircularDependencies();}private void detectCircularDependencies() {String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {try {// 尝试创建 Bean,触发循环依赖检测Object bean = beanFactory.getBean(beanName);System.out.println("成功创建: " + beanName);} catch (BeanCurrentlyInCreationException e) {System.err.println("循环依赖 detected: " + e.getMessage());}}}
}

    8.3 查看缓存状态

@Component
public class CacheStatusLogger implements ApplicationRunner {@Autowiredprivate AbstractApplicationContext context;@Overridepublic void run(ApplicationArguments args) throws Exception {DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) context.getBeanFactory();// 通过反射查看缓存状态printCacheStatus(registry, "singletonObjects");printCacheStatus(registry, "earlySingletonObjects");printCacheStatus(registry, "singletonFactories");}private void printCacheStatus(DefaultSingletonBeanRegistry registry, String cacheName) {try {Field field = DefaultSingletonBeanRegistry.class.getDeclaredField(cacheName);field.setAccessible(true);Map<?, ?> cache = (Map<?, ?>) field.get(registry);System.out.println(cacheName + " size: " + cache.size());System.out.println(cacheName + " keys: " + cache.keySet());} catch (Exception e) {e.printStackTrace();}}
}

9. Spring Boot 配置选项

    9.1 相关配置属性

##########  application.properties##########  是否允许循环引用(默认 true)
spring.main.allow-circular-references=true##########  是否允许 Bean 定义覆盖(默认 false)  
spring.main.allow-bean-definition-overriding=false##########  懒初始化(可以帮助避免某些循环依赖)
spring.main.lazy-initialization=false

    9.2 禁用循环依赖支持

@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication application = new SpringApplication(Application.class);// 禁用循环引用application.setAllowCircularReferences(false);application.run(args);}
}

10. 总结

Spring 通过三级缓存机制解决循环依赖的核心要点:

    解决的条件:

  • 单例 Bean
  • Setter/字段注入
  • 非构造器注入

    无法解决的情况:

  • 构造器循环依赖
  • 原型 Bean 循环依赖
  • @Async 等方法级别的代理

    核心原理:

  1. 提前暴露:Bean 实例化后立即暴露到三级缓存
  2. 工厂模式:通过 ObjectFactory 延迟决定返回原始对象还是代理对象
  3. 缓存升级:从三级缓存 → 二级缓存 → 一级缓存
  4. AOP 支持:在早期引用阶段处理代理逻辑

    最佳实践:

  1. 优先使用 Setter 注入而非构造器注入
  2. 使用 @Lazy 注解打破循环依赖
  3. 合理设计代码结构,避免循环依赖
  4. 在必要时进行代码重构

理解 Spring 的循环依赖解决机制对于设计复杂的 Spring 应用、排查启动问题以及进行性能优化都具有重要意义。



























Spring的三级缓存原理 笔记251008

Spring 如何解决循环依赖 笔记251008

Spring的 三级缓存 与 AOP 笔记251009

Spring的第三级缓存详解 笔记251009

http://www.dtcms.com/a/457256.html

相关文章:

  • Coze源码分析-资源库-编辑数据库-后端源码-应用/领域/数据访问/基础设施层
  • 北京建设网站的公司兴田德润简介济南网站建设平台官网
  • 力扣 —— 动态规划(背包问题)
  • 基础微网站开发代理商wordpress图文模板
  • bind,apply,call
  • 最新ECCV最新大感受野的小波卷积
  • 小迪web自用笔记59
  • Docker 容器核心知识总结
  • GIS+VR地理信息虚拟现实XR MR AR
  • K8s学习笔记(十四) DaemonSet
  • 视频网站建设应该注意什么北京建设网点地址查询
  • 面试技术栈 —— 简历篇
  • Python闭包内变量访问详解:从原理到高级实践
  • DNS隧道技术:隐秘通信的“毛细血管”通道
  • MySQL 性能监控与安全管理完全指南
  • 【Linux】进程控制(上)
  • 湖北省建设网站wordpress商务套餐
  • 网站建设推广的软文邢台建站企业邮箱
  • C++11并发支持库
  • 广东省省考备考(第一百一十八天10.8)——言语、资料分析、数量关系(强化训练)
  • 临沂网站制作页面如何查一个网站有没有做外链
  • 基于websocket的多用户网页五子棋(八)
  • Elastic 被评为 IDC MarketScape《2025 年全球扩展检测与响应软件供应商评估》中的领导者
  • 如何利用Python呼叫nexxim.exe执行电路模拟
  • APM学习(3):ArduPilot飞行模式
  • h5制作开发价目表常用seo站长工具
  • 忻州建设公司网站他达那非副作用太强了
  • pytest详细教程
  • 订单超时方案的选择
  • Redis 集群故障转移