Spring的三级缓存原理 笔记251008

- 一级缓存存储: 完成实例化,完成属性注入 的Bean
- 二级缓存存储: 完成实例化,未完成属性注入 的Bean
- 三级缓存存储: Bean的工厂 (Bean还没有实例化)
Spring 的三级缓存是 Singleton 三级缓存体系 ,用于解决 循环依赖 问题,尤其是 单例 Bean 的循环依赖 。它的核心思想是:提前暴露未完全初始化的 Bean 的引用,让其他 Bean 可以先引用它,从而打破循环依赖的死锁。
✅ 三级缓存的结构(DefaultSingletonBeanRegistry)
Spring 的三级缓存是在 DefaultSingletonBeanRegistry 中定义的,分别是:
| 缓存名称 | 变量名 | 作用 | 
|---|---|---|
| 一级缓存 | singletonObjects | 存放 完全初始化好 的单例 Bean(最终成品) | 
| 二级缓存 | earlySingletonObjects | 存放 提前暴露 的单例 Bean(半成品,已实例化但未初始化) | 
| 三级缓存 | singletonFactories | 存放 ObjectFactory,用于生成早期引用(支持 AOP 代理) | 
✅ 三级缓存解决循环依赖的流程
假设有两个 Bean:A 和 B,它们互相依赖:
            
            
              java
              
              
            
          
          class A {
    @Autowired
    private B b;
}
class B {
    @Autowired
    private A a;
}步骤如下:
- 创建 A 的实例(构造函数)→ 完成实例化,但未初始化。
- 将 A 的 ObjectFactory 放入三级缓存 (singletonFactories)。
- 填充 A 的属性 → 发现需要 B。
- 创建 B 的实例 → 完成实例化,未初始化。
- B 填充属性 → 发现需要 A。
- 从三级缓存中获取 A 的 ObjectFactory ,调用 getObject()获取早期引用(可能是代理对象),放入二级缓存。
- B 完成初始化 → 放入一级缓存。
- A 继续填充属性 → 拿到 B 的完整对象。
- A 完成初始化 → 放入一级缓存。
✅ 为什么需要三级缓存?二级不行吗?
- 二级缓存(earlySingletonObjects) 只能存 Bean 的早期引用。
- 三级缓存(singletonFactories) 存的是 ObjectFactory,可以 延迟创建代理对象 ,支持 AOP 代理。
如果只有二级缓存,AOP 代理对象必须在实例化后立即创建,这违反了 Spring 的设计原则(代理在初始化后创建)。
三级缓存通过
ObjectFactory.getObject()延迟创建代理,保证了 生命周期一致性。
✅ 总结一句话
三级缓存的核心作用是:通过提前暴露 ObjectFactory,支持循环依赖,并保证 AOP 代理的正确创建时机。
✅ 图示(简化)
            
            
              text
              
              
            
          
          singletonObjects(一级) ← 最终成品
↑
earlySingletonObjects(二级) ← 早期引用(从三级缓存拿)
↑
singletonFactories(三级) ← ObjectFactory(延迟创建代理)✅ 注意
- 仅支持单例 Bean 的循环依赖。
- 原型 Bean(prototype)不支持循环依赖,会直接抛异常。
- 构造器注入的循环依赖无法解决(因为实例化阶段就卡住了)。
需要我帮你画个流程图或贴源码分析吗?
Spring 三级缓存原理详解
1. 循环依赖问题与三级缓存的引入
1.1 循环依赖问题
            
            
              java
              
              
            
          
          @Service
public class UserService {
    @Autowired
    private OrderService orderService;
}
@Service 
public class OrderService {
    @Autowired
    private UserService userService;
}上述代码会产生循环依赖:UserService → OrderService → UserService
1.2 三级缓存的作用
Spring 通过三级缓存机制解决单例 Bean 的循环依赖问题。
2. 三级缓存定义与层次
2.1 三级缓存定义
在 DefaultSingletonBeanRegistry 类中定义:
            
            
              java
              
              
            
          
          public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    
    // 一级缓存:完整的单例 Bean
    private 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 创建的核心流程
            
            
              java
              
              
            
          
          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 三级缓存的添加时机
            
            
              java
              
              
            
          
          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 详细解决流程
            
            
              java
              
              
            
          
          // 获取 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. 从三级缓存获取 ObjectFactory
                ObjectFactory<?> 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 循环依赖解决示例
以 UserService 和 OrderService 为例:
            
            
              java
              
              
            
          
          // UserService 创建过程
1. 开始创建 UserService
2. 实例化 UserService(原始对象)
3. 将 UserService 的 ObjectFactory 放入三级缓存
4. 属性填充:发现需要 OrderService
5. 开始创建 OrderService
// OrderService 创建过程  
6. 实例化 OrderService(原始对象)
7. 将 OrderService 的 ObjectFactory 放入三级缓存
8. 属性填充:发现需要 UserService
9. 获取 UserService:
   - 一级缓存:无
   - 二级缓存:无  
   - 三级缓存:找到 UserService 的 ObjectFactory
   - 通过 ObjectFactory 获取 UserService 的早期引用
   - 将 UserService 从三级缓存移到二级缓存
10. OrderService 完成属性填充和初始化
11. OrderService 放入一级缓存
// 回到 UserService 创建
12. UserService 完成属性填充(注入 OrderService)
13. UserService 完成初始化
14. UserService 放入一级缓存,从二级缓存移除5. AOP 代理与三级缓存
5.1 代理对象的特殊处理
            
            
              java
              
              
            
          
          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 代理场景示例
            
            
              java
              
              
            
          
          @Service
public class UserService {
    @Autowired
    private OrderService orderService;
    
    @Transactional
    public void updateUser() {
        // 事务方法
    }
}
@Service
public class OrderService {
    @Autowired
    private UserService userService;  // 这里需要注入代理对象
}处理流程:
- UserService实例化后,三级缓存中的- ObjectFactory会检查是否需要 AOP 代理
- 如果需要代理,getEarlyBeanReference返回代理对象
- OrderService注入的是- UserService的代理对象
- 保证事务等 AOP 功能正常工作
6. 源码深度解析
6.1 核心源码分析
            
            
              java
              
              
            
          
          public class DefaultSingletonBeanRegistry {
    
    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 第一级检查:完全初始化的 Bean
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 第二级检查:早期引用
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    // 第三级检查:ObjectFactory
                    ObjectFactory<?> 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 创建完整流程
            
            
              java
              
              
            
          
          public abstract class AbstractAutowireCapableBeanFactory {
    
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
        // 1. 实例化 Bean
        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);
        
        // 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 构造器循环依赖
            
            
              java
              
              
            
          
          @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 原型模式的循环依赖
            
            
              java
              
              
            
          
          @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {
    @Autowired
    private OrderService orderService;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
@Service
public class OrderService {
    @Autowired
    private UserService userService;
}结果:原型 Bean 的循环依赖无法解决,因为三级缓存只针对单例 Bean
8. 三级缓存的设计原理
8.1 为什么需要三级缓存?
一级缓存的作用:
- 存储完全初始化好的 Bean
- 提供最终的单例实例
二级缓存的作用:
- 存储早期暴露的对象
- 避免重复创建代理对象
三级缓存的作用:
- 存储创建 Bean 的工厂
- 支持 AOP 代理等后处理器的介入
8.2 三级缓存的必要性
            
            
              java
              
              
            
          
          // 如果只有二级缓存,没有三级缓存:
// 在属性填充阶段,如果 Bean 需要被代理,我们无法知道应该返回原始对象还是代理对象
// 三级缓存通过 ObjectFactory 延迟决策:
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
    // 在这里决定返回原始对象还是代理对象
    singletonObject = singletonFactory.getObject();
}9. 实际应用与调试
9.1 调试三级缓存
            
            
              java
              
              
            
          
          @Component
public class CacheDebugger implements ApplicationRunner {
    
    @Autowired
    private AbstractApplicationContext context;
    
    @Override
    public 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 循环依赖检测
            
            
              java
              
              
            
          
          @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 避免循环依赖
最佳实践:
- 使用 setter 注入而非构造器注入
- 使用 @Lazy注解延迟加载
- 重构代码,消除循环依赖
10.2 @Lazy 注解的使用
            
            
              java
              
              
            
          
          @Service
public class UserService {
    @Lazy  // 延迟注入,打破循环依赖
    @Autowired
    private OrderService orderService;
}
@Service
public class OrderService {
    @Autowired
    private UserService userService;
}10.3 应用启动参数
            
            
              properties
              
              
            
          
          # 禁用循环引用(不推荐,但可用于调试)
spring.main.allow-circular-references=false
# 允许注入原始 Bean(即使有 AOP 包装)
spring.main.allow-bean-definition-overriding=true总结
Spring 三级缓存机制的核心要点:
- 解决什么问题:单例 Bean 的循环依赖
- 核心思想:提前暴露未完全初始化的 Bean 引用
- 三级缓存分工 :
- 一级缓存:完整的 Bean
- 二级缓存:早期的 Bean 引用
- 三级缓存:Bean 创建工厂
 
- 关键时机:实例化后、属性填充前添加到三级缓存
- 特殊处理:支持 AOP 代理等后处理器
- 限制条件:无法解决构造器循环依赖和原型 Bean 循环依赖
理解三级缓存原理对于深入掌握 Spring IoC 容器的工作机制、排查循环依赖问题以及进行性能优化都具有重要意义。
1️⃣ 参考 1
Spring 三级缓存原理详解
1. 什么是三级缓存
Spring 的三级缓存是解决循环依赖问题的核心机制。它通过在 Bean 创建的不同阶段将 Bean 对象存储在不同的缓存中,从而允许其他 Bean 在依赖注入时能够获取到尚未完全初始化的 Bean 引用。
2. 三级缓存的具体定义
在 DefaultSingletonBeanRegistry 类中定义了三层缓存:
            
            
              java
              
              
            
          
          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 的完整生命周期
            
            
              java
              
              
            
          
          // 简化的 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
            
            
              java
              
              
            
          
          @Component
public class A {
    @Autowired
    private B b;
}
@Component  
public class B {
    @Autowired
    private A a;
}创建流程:
- 
开始创建 A java// A 开始创建,加入创建中集合 singletonsCurrentlyInCreation.add("a"); // 实例化 A 对象 Object a = new A(); // 将 A 的 ObjectFactory 放入三级缓存 addSingletonFactory("a", () -> getEarlyBeanReference("a", mbd, a));
- 
A 进行属性注入,发现依赖 B java// 在注入 B 时,会调用 getBean("b") // 此时 A 还在创建中,但已经在三级缓存中有工厂对象
- 
开始创建 B javasingletonsCurrentlyInCreation.add("b"); Object b = new B(); addSingletonFactory("b", () -> getEarlyBeanReference("b", mbd, b));
- 
B 进行属性注入,发现依赖 A java// 调用 getBean("a") 获取 A // 发现 A 正在创建中 (singletonsCurrentlyInCreation.contains("a")) // 从三级缓存获取 A 的早期引用 Object aEarly = getSingleton("a", true);
- 
获取 A 的早期引用流程 javaprotected 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; }
- 
B 完成创建 java// B 完成属性注入和初始化 // 将 B 放入一级缓存,清除二三级缓存 addSingleton("b", b);
- 
A 完成创建 java// 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 代理的特殊情况
            
            
              java
              
              
            
          
          @Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired 
    private A a;  // 这里需要的是 A 的代理对象,而不是原始对象
}
@Configuration
@EnableAspectJAutoProxy
public class Config {
    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}三级缓存的关键代码:
            
            
              java
              
              
            
          
          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 方法
            
            
              java
              
              
            
          
          public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 三级缓存查找逻辑
    // 1. 一级缓存 → 2. 二级缓存 → 3. 三级缓存
}6.2 addSingletonFactory 方法
            
            
              java
              
              
            
          
          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 方法
            
            
              java
              
              
            
          
          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 构造器循环依赖
            
            
              java
              
              
            
          
          @Component
public class A {
    private final B b;
    
    @Autowired
    public 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 作用域的循环依赖
            
            
              java
              
              
            
          
          @Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {
    @Autowired
    private B b;  // Prototype 作用域,无法解决循环依赖
}8. 总结
Spring 的三级缓存机制:
- 一级缓存:完整 Bean,可直接使用
- 二级缓存:早期 Bean,解决普通循环依赖
- 三级缓存:Bean 工厂,处理 AOP 代理等复杂情况
核心价值:通过分层缓存和延迟创建策略,优雅地解决了 Spring 中的循环依赖问题,同时保证了 Bean 创建的正确性和一致性。
设计思想:空间换时间,通过多级缓存平衡了性能与功能的矛盾,体现了 Spring 框架设计的精妙之处。
2️⃣ 参考 2
Spring 三级缓存原理详解
概述
Spring 的三级缓存是解决循环依赖问题的核心机制。通过三级缓存的设计,Spring 能够在 Bean 创建过程中处理相互依赖的情况。
三级缓存定义
在 DefaultSingletonBeanRegistry 类中定义了三级缓存:
            
            
              java
              
              
            
          
          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
            
            
              java
              
              
            
          
          @Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}创建过程详解
- 开始创建 A
            
            
              java
              
              
            
          
          // 步骤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. 从三级缓存获取ObjectFactory
                ObjectFactory<?> 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 的详细步骤:
- 
实例化 A java// 调用构造方法创建A实例 instanceWrapper = createBeanInstance(beanName, mbd, args); Object bean = instanceWrapper.getWrappedInstance();
- 
将 A 的 ObjectFactory 放入三级缓存 java// 在 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); } } }
- 
属性注入 - 发现依赖 B java// 在 populateBean 方法中 for (BeanReference beanReference : beanReferences) { // 发现需要注入B,开始获取或创建B String refName = beanReference.getBeanName(); Object refBean = getBean(refName); }
- 
开始创建 B 
- 
实例化 B 
- 
将 B 的 ObjectFactory 放入三级缓存 
- 
属性注入 - 发现依赖 A 
- 
B 获取 A 的流程 
            
            
              java
              
              
            
          
          // 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;
}- 完成创建过程
            
            
              java
              
              
            
          
          // 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 方法
            
            
              java
              
              
            
          
          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 创建流程
            
            
              java
              
              
            
          
          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. 构造器循环依赖(无法解决)
            
            
              java
              
              
            
          
          @Component
public class A {
    private B b;
    
    @Autowired
    public A(B b) {  // 构造器注入
        this.b = b;
    }
}
@Component
public class B {
    private A a;
    
    @Autowired
    public B(A a) {  // 构造器注入
        this.a = a;
    }
}原因:在构造器阶段就需要完整的依赖对象,而此时 Bean 还未实例化,无法放入三级缓存。
2. 原型模式的循环依赖(无法解决)
            
            
              java
              
              
            
          
          @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {
    @Autowired
    private PrototypeB b;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {
    @Autowired
    private PrototypeA a;
}原因:原型模式不缓存 Bean 实例,每次都会创建新实例。
3. 有 AOP 代理的情况
            
            
              java
              
              
            
          
          @Component
public class A {
    @Autowired
    private B b;
    
    public void businessMethod() {
        // 业务方法
    }
}
@Aspect
@Component
public class LogAspect {
    @Before("execution(* com.example.A.businessMethod(..))")
    public void logBefore() {
        System.out.println("方法执行前日志");
    }
}处理流程:
- 创建 A 的原始对象
- 将 A 的 ObjectFactory 放入三级缓存
- ObjectFactory 的 getEarlyBeanReference方法会调用 AOP 相关的后处理器
- 返回 A 的代理对象作为早期引用
三级缓存总结
| 缓存级别 | 存储内容 | 作用 | 生命周期 | 
|---|---|---|---|
| 一级缓存 | 完整的单例 Bean | 提供最终可用的 Bean | Bean 完全初始化后放入 | 
| 二级缓存 | 早期暴露的 Bean | 避免重复创建代理对象 | 从三级缓存升级而来,最终移入一级缓存 | 
| 三级缓存 | ObjectFactory | 创建早期引用,处理 AOP | Bean 实例化后放入,第一次获取后移除 | 
设计思想
- 分离关注点:实例化、依赖注入、初始化分离
- 空间换时间:通过缓存提高性能
- 懒加载思想:ObjectFactory 延迟创建早期引用
- 代理兼容:支持 AOP 等增强功能
最佳实践
- 避免构造器循环依赖
- 优先使用 setter 注入
- 合理设计 Bean 依赖关系
- 了解缓存机制,优化性能
三级缓存机制是 Spring 框架解决循环依赖问题的精妙设计,理解其原理对于深入掌握 Spring IoC 容器至关重要。
3️⃣ 参考 3
Spring 三级缓存原理详解
1. 三级缓存概述
Spring 的三级缓存是解决循环依赖问题的核心机制。所谓循环依赖,就是两个或多个 Bean 相互依赖,形成依赖闭环。
2. 三级缓存定义
在 DefaultSingletonBeanRegistry 类中定义了三级缓存:
            
            
              java
              
              
            
          
          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 创建的基本流程
            
            
              java
              
              
            
          
          // 简化版的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
            
            
              java
              
              
            
          
          @Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}4.2 详细解决流程
            
            
              java
              
              
            
          
          // 创建A的过程
1. getBean("A")
   → 从一级缓存singletonObjects获取A,不存在
   → 标记A为创建中:singletonsCurrentlyInCreation.add("A")
   → 实例化A对象(此时A是个半成品,b=null)
2. 将A的ObjectFactory放入三级缓存
   addSingletonFactory("A", () -> getEarlyBeanReference("A", mbd, a))
3. 属性注入:发现A依赖B
   → getBean("B")
// 创建B的过程
4. getBean("B")
   → 从一级缓存获取B,不存在
   → 标记B为创建中:singletonsCurrentlyInCreation.add("B")
   → 实例化B对象
5. 将B的ObjectFactory放入三级缓存
   addSingletonFactory("B", () -> getEarlyBeanReference("B", mbd, b))
6. 属性注入:发现B依赖A
   → getBean("A")
7. 再次获取A
   → 一级缓存:没有
   → 二级缓存:没有
   → 三级缓存:找到A的ObjectFactory
   → 调用ObjectFactory.getObject()获取A的早期引用
   → 将A从三级缓存移到二级缓存
   → 返回A的早期引用给B
8. B完成属性注入(此时B持有A的早期引用)
9. B完成初始化,放入一级缓存
   → 从三级缓存移除B的ObjectFactory
   → 从二级缓存移除B(如果有)
   → singletonObjects.put("B", b)
// 回到A的创建
10. A获得B的完整实例,完成属性注入
11. A完成初始化,放入一级缓存
    → 从三级缓存移除A的ObjectFactory
    → 从二级缓存移除A
    → singletonObjects.put("A", a)4.3 缓存状态变化时序图
时间轴:      t1      t2      t3      t4      t5      t6
创建A:      开始实例化 → 放入三级缓存 → 属性注入需要B →              → 完成初始化
创建B:                     开始实例化 → 放入三级缓存 → 属性注入需要A → 完成初始化
三级缓存A:        空       有A工厂       有A工厂       空           空
二级缓存A:        空         空         空         有A早期引用     空
一级缓存A:        空         空         空         空           有A完整Bean5. 源码关键方法解析
5.1 getSingleton 方法
            
            
              java
              
              
            
          
          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
                ObjectFactory<?> 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 方法
            
            
              java
              
              
            
          
          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 方法
            
            
              java
              
              
            
          
          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 构造器循环依赖(无法解决)
            
            
              java
              
              
            
          
          @Component
public class A {
    private B b;
    
    @Autowired
    public A(B b) {  // 构造器注入,无法解决循环依赖
        this.b = b;
    }
}
@Component
public class B {
    private A a;
    
    @Autowired
    public B(A a) {  // 构造器注入,无法解决循环依赖
        this.a = a;
    }
}原因:在构造器注入时,Bean 还没有实例化,无法将 ObjectFactory 放入三级缓存。
6.2 原型(Prototype)作用域的循环依赖(无法解决)
            
            
              java
              
              
            
          
          @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeA {
    @Autowired
    private PrototypeB b;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class PrototypeB {
    @Autowired
    private PrototypeA a;
}原因:原型 Bean 不缓存,每次都会创建新实例。
7. 与 AOP 的协同工作
7.1 代理对象的处理
            
            
              java
              
              
            
          
          @Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
    
    @Transactional  // 需要AOP代理
    public void method() {
        // ...
    }
}
@Component  
public class ServiceB {
    @Autowired
    private ServiceA serviceA;  // 这里注入的应该是代理对象
}处理过程:
- 在 getEarlyBeanReference方法中,AbstractAutoProxyCreator会创建代理对象
- 三级缓存中存储的是能返回代理对象的 ObjectFactory
- 当发生循环依赖时,返回的是代理对象而不是原始对象
8. 总结
8.1 三级缓存的作用
- 一级缓存:存储完全初始化好的 Bean,可直接使用
- 二级缓存:存储早期的 Bean 引用,用于避免重复创建代理对象
- 三级缓存:存储 Bean 工厂,用于创建早期引用并处理 AOP 代理
8.2 解决循环依赖的条件
- 必须是单例 Bean
- 不能是构造器注入(必须是字段注入或 setter 注入)
- 依赖的 Bean 必须能被提前暴露
8.3 设计思想
Spring 的三级缓存机制体现了"空间换时间 "和"关注点分离"的设计思想,通过缓存不同状态的 Bean 来优雅地解决复杂的循环依赖问题,同时保证了 Bean 创建过程的正确性和性能。
4️⃣ 参考 4
Spring 三级缓存原理详解
1. 循环依赖问题
1.1 什么是循环依赖
            
            
              java
              
              
            
          
          @Service
public class AService {
    @Autowired
    private BService bService;
}
@Service
public class BService {
    @Autowired
    private AService aService;
}这种相互依赖的情况就是循环依赖。
2. 三级缓存结构
Spring 通过三级缓存来解决循环依赖问题:
2.1 三级缓存定义
            
            
              java
              
              
            
          
          public class DefaultSingletonBeanRegistry {
    // 一级缓存:完整的单例 Bean
    private 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));
}3. Bean 创建流程与三级缓存
3.1 Bean 创建的主要步骤
            
            
              java
              
              
            
          
          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 的创建过程
            
            
              java
              
              
            
          
          // 创建 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 源码中的关键方法
            
            
              java
              
              
            
          
          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 代理对象的循环依赖问题。
            
            
              java
              
              
            
          
          // 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 构造器循环依赖(无法解决)
            
            
              java
              
              
            
          
          @Service
public class AService {
    private final BService bService;
    
    @Autowired
    public AService(BService bService) {
        this.bService = bService;
    }
}
@Service  
public class BService {
    private final AService aService;
    
    @Autowired
    public BService(AService aService) {
        this.aService = aService;
    }
}结果 :Spring 会抛出 BeanCurrentlyInCreationException
6.2 原型模式的循环依赖
            
            
              java
              
              
            
          
          @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class AService {
    @Autowired
    private BService bService;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)  
@Service
public class BService {
    @Autowired
    private AService aService;
}结果 :Spring 会抛出 BeanCurrentlyInCreationException
7. 源码调试示例
7.1 调试关键点
            
            
              java
              
              
            
          
          // 断点设置位置:
1. DefaultSingletonBeanRegistry.getSingleton()
2. AbstractAutowireCapableBeanFactory.doCreateBean()
3. AbstractAutowireCapableBeanFactory.createBeanInstance()
4. AbstractAutowireCapableBeanFactory.populateBean()
// 观察三级缓存的变化:
- singletonObjects: 一级缓存
- earlySingletonObjects: 二级缓存  
- singletonFactories: 三级缓存
- singletonsCurrentlyInCreation: 正在创建的 Bean8. 总结
8.1 三级缓存的核心价值
- 解决循环依赖:通过提前暴露对象引用
- 保证单例:确保整个过程中只有一个 Bean 实例
- 支持 AOP:正确处理代理对象的循环依赖
8.2 使用建议
- 避免构造器循环依赖:使用 @Autowired 字段注入或 setter 注入
- 理解作用域限制:只有单例 Bean 能解决循环依赖
- 合理设计架构:尽量减少循环依赖,提高代码可维护性
8.3 核心流程图
Bean 实例化 → 加入三级缓存 → 属性注入 → 遇到依赖
    ↓
依赖 Bean 创建 → 需要原始 Bean → 从三级缓存获取
    ↓  
ObjectFactory.getObject() → 可能返回代理对象 → 升级到二级缓存
    ↓
依赖 Bean 完成创建 → 原始 Bean 继续初始化 → 升级到一级缓存通过三级缓存机制,Spring 优雅地解决了单例 Bean 的循环依赖问题,同时保证了 Bean 创建过程的正确性和一致性。
5️⃣ 参考 5
Spring的三级缓存是Spring框架为解决单例Bean循环依赖问题而设计的核心机制,通过分阶段缓存Bean实例的不同状态,确保在依赖注入过程中避免重复创建和死循环。以下是其原理的详细说明:
一、三级缓存的组成
Spring的三级缓存由三个Map结构组成,分别存储Bean在不同生命周期阶段的状态:
- 
一级缓存(SingletonObjects) - 作用:存储已完全初始化好的单例Bean。
- 特点 :Bean已完成所有依赖注入和初始化(如@Autowired、@PostConstruct等),可直接供其他Bean使用。
- 数据结构 :ConcurrentHashMap<String, Object>,线程安全。
 
- 
二级缓存(EarlySingletonObjects) - 作用:存储已实例化但未完全初始化的Bean(半成品Bean)。
- 特点:Bean已完成实例化(如通过构造器或工厂方法创建),但尚未完成属性注入和初始化。
- 使用场景:当Bean存在循环依赖时,提前暴露半成品Bean供其他Bean引用。
- 数据结构 :HashMap<String, Object>,非线程安全(因一级缓存已保证线程安全)。
 
- 
三级缓存(SingletonFactories) - 作用 :存储Bean的工厂对象(ObjectFactory),用于动态生成代理对象或原始对象。
- 特点 :
- 解决AOP代理问题:若Bean需要被代理(如@Transactional、@Async等),工厂对象可按需生成代理对象或原始对象。
- 避免重复创建:通过Lambda表达式延迟对象生成,确保单例Bean的唯一性。
 
- 解决AOP代理问题:若Bean需要被代理(如
- 数据结构 :HashMap<String, ObjectFactory<?>>,存储工厂接口。
 
- 作用 :存储Bean的工厂对象(
二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:
- 
创建Bean A - Spring从一级缓存查找Bean A,未找到。
- 创建Bean A的实例(调用构造器),并将其放入三级缓存(存储工厂对象)。
- 开始属性注入,发现依赖Bean B。
 
- 
创建Bean B - Spring从一级缓存查找Bean B,未找到。
- 创建Bean B的实例,并将其放入三级缓存。
- 开始属性注入,发现依赖Bean A。
 
- 
解决Bean A的循环依赖 - Spring从一级缓存查找Bean A,未找到;从二级缓存查找,未找到。
- 从三级缓存获取Bean A的工厂对象,调用getObject()生成半成品Bean A(可能是代理对象)。
- 将半成品Bean A放入二级缓存,并从三级缓存移除。
- 将半成品Bean A注入Bean B。
 
- 
完成Bean B的初始化 - Bean B完成属性注入和初始化(如调用init-method)。
- 将完全初始化的Bean B放入一级缓存,并从二级缓存移除。
 
- Bean B完成属性注入和初始化(如调用
- 
完成Bean A的初始化 - Spring继续Bean A的属性注入,从一级缓存获取完全初始化的Bean B。
- Bean A完成初始化,放入一级缓存,并从二级缓存移除。
 
三、三级缓存的核心作用
- 
解决循环依赖 - 通过提前暴露半成品Bean,打破循环依赖的死锁。
- 例如:Bean A依赖Bean B,Bean B依赖Bean A时,三级缓存确保Bean A的半成品可被Bean B引用。
 
- 
支持AOP代理 - 三级缓存的工厂对象可按需生成代理对象,避免代理对象与原始对象冲突。
- 例如:若Bean A需要被代理,工厂对象会返回代理对象而非原始对象。
 
- 
保证单例唯一性 - 通过一级缓存确保每个Bean仅初始化一次,避免重复创建。
 
- 
提升性能 - 缓存半成品Bean减少重复实例化开销,加速Bean创建过程。
 
四、源码解析
关键方法位于DefaultSingletonBeanRegistry类中:
- 
getSingleton(String beanName, boolean allowEarlyReference)- 按一级缓存→二级缓存→三级缓存的顺序查找Bean。
- 若从三级缓存获取,则调用工厂对象生成Bean,并升级到二级缓存。
 javaprotected 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; }
- 
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)- 将Bean的工厂对象存入三级缓存,用于后续循环依赖处理。
 
五、限制与注意事项
- 
仅支持单例Bean - 多例(Prototype)Bean无法通过三级缓存解决循环依赖,因每次请求都会创建新实例。
 
- 
构造器注入的局限性 - 若循环依赖通过构造器注入(如public A(B b) {}),三级缓存无法解决,会抛出BeanCurrentlyInCreationException。
- 解决方案:改用Setter注入或字段注入。
 
- 若循环依赖通过构造器注入(如
- 
AOP代理的兼容性 - 若Bean未被代理,三级缓存可简化为二级缓存(直接存储半成品Bean)。
- 但为统一处理代理场景,Spring始终使用三级缓存。
 
6️⃣ 参考 6
Spring三级缓存原理详解
Spring三级缓存是Spring框架解决Bean循环依赖问题的核心机制,通过"提前暴露半成品Bean"的方式,确保即使存在循环依赖也能正确初始化Bean。
三级缓存结构
- 
一级缓存 (singletonObjects) - 存储完全初始化后的单例Bean
- ConcurrentHashMap实现,Key为beanName
- 是最终可以被使用的Bean实例
 
- 
二级缓存 (earlySingletonObjects) - 存储已实例化但未初始化的"早期引用"
- HashMap实现
- 用于解决AOP代理问题
 
- 
三级缓存 (singletonFactories) - 存储ObjectFactory函数式接口
- 通过getObject()方法生成代理对象
- 用于在Bean创建过程中提前暴露未完成的Bean
 
工作流程
当Spring容器需要获取一个Bean时,会按照以下顺序查询缓存:
先查一级缓存 → 无
查二级缓存 → 无
查三级缓存 → 执行ObjectFactory循环依赖解决示例
以A依赖B,B依赖A的循环依赖为例:
- Spring先实例化A(A是半成品,属性未注入)
- 为A创建ObjectFactory,并放入三级缓存
- A需要注入B,开始实例化B
- B需要注入A,此时在三级缓存中找到A的ObjectFactory
- 通过ObjectFactory获取A的半成品对象
- B完成初始化,放入一级缓存
- A继续完成初始化,放入一级缓存
重要特性与限制
- 
适用范围: - 仅适用于Singleton作用域的Bean
- 无法解决构造器注入的循环依赖(会抛出BeanCurrentlyInCreationException异常)
 
- 
AOP代理处理: - 在getEarlyBeanReference方法中,如果有AOP配置,会在此生成代理对象
 
- 
多线程问题: - 三级缓存机制在多线程环境下仍可能出现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的不同状态,按"完成度"从高到低分为:
- 
一级缓存(singletonObjects) 类型: Map<String, Object>作用:存储完全初始化完成的单例Bean(已实例化、属性注入、初始化方法执行完毕)。这是最终供用户使用的Bean。 
- 
二级缓存(earlySingletonObjects) 类型: Map<String, Object>作用:存储提前暴露的早期Bean实例(已实例化,但未完成属性注入和初始化)。这些实例可能是原始对象,也可能是经过AOP代理的对象(若Bean需要被代理)。 
- 
三级缓存(singletonFactories) 类型: Map<String, ObjectFactory<?>>作用:存储Bean的工厂对象(ObjectFactory)。工厂的作用是在需要时生成早期Bean实例(可能触发AOP代理创建),避免提前生成代理对象造成资源浪费。 
二、三级缓存的工作流程(以A依赖B,B依赖A为例)
- 
创建Bean A的流程 - 步骤1:Spring启动时,触发Bean A的创建,先检查一级缓存(singletonObjects),若不存在则继续。
- 步骤2:实例化A(调用构造器生成原始对象),此时A尚未完成属性注入和初始化。
- 步骤3:将A的工厂对象(ObjectFactory)放入三级缓存(singletonFactories)。工厂的逻辑是:若A需要AOP代理,则生成代理对象;否则返回原始对象。
- 步骤4:开始为A注入属性,发现依赖B,此时触发Bean B的创建。
 
- 
创建Bean B的流程 - 步骤1:检查一级缓存,B不存在,继续创建。
- 步骤2:实例化B,将B的工厂放入三级缓存。
- 步骤3:为B注入属性,发现依赖A,开始查找A。
 
- 
解决B对A的依赖 - 步骤1:查找A时,先查一级缓存(A未完成,无),再查二级缓存(无),最后查三级缓存(存在A的工厂)。
- 步骤2:通过A的工厂生成A的早期实例(若A需要代理,则此处生成代理对象),并将该实例从三级缓存移至二级缓存(earlySingletonObjects)。
- 步骤3:将A的早期实例注入B,B完成属性注入和初始化,放入一级缓存(singletonObjects)。
 
- 
完成A的创建 - B创建完成后,回到A的属性注入步骤,将B从一级缓存中取出并注入A。
- A完成属性注入和初始化,放入一级缓存(singletonObjects),同时从二级缓存中移除A的早期实例。
 
三、为什么需要三级缓存?
核心原因是处理AOP代理场景下的循环依赖:
- 若仅用两级缓存(一级+二级),提前暴露的Bean只能是原始对象。但如果Bean需要AOP代理(如被@Transactional注解),最终应使用代理对象,而原始对象注入后会导致不一致(注入的是原始对象,最终容器中是代理对象)。
- 三级缓存的工厂(ObjectFactory)实现了"延迟生成代理":只有当循环依赖发生时,才会通过工厂生成代理对象并放入二级缓存,避免了无循环依赖时不必要的代理创建,同时保证注入的是正确的代理对象。
四、适用范围与限制
- 仅支持单例Bean :原型Bean(scope="prototype")每次创建都是新实例,无法缓存,因此循环依赖会直接报错。
- 不支持构造器循环依赖:若A的构造器依赖B,B的构造器依赖A,由于实例化(构造器调用)前无法生成工厂对象,三级缓存无法生效,会报错。
- 依赖必须通过setter注入或字段注入:只有实例化后(构造器执行完),才能通过工厂提前暴露Bean,因此构造器注入无法解决循环依赖。
总结:三级缓存通过"提前暴露工厂→按需生成早期实例→最终完善Bean"的流程,既解决了单例Bean的循环依赖问题,又兼顾了AOP代理的正确性,是Spring容器设计的精妙之处。
8️⃣ 参考 8
Spring三级缓存原理详解
Spring的三级缓存机制是解决单例Bean循环依赖的核心设计,其工作原理如下:
- 三级缓存的定义
            
            
              java
              
              
            
          
          // Spring容器中的三级缓存
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存:完整Bean
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 二级缓存:半成品Bean
Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(); // 三级缓存:Bean工厂- 
解决循环依赖的流程(以A→B→A为例) 
- 
创建A实例 - 实例化A(调用构造函数),此时A是原始对象
- 将A的ObjectFactory存入三级缓存:singletonFactories.put("a", () -> getEarlyBeanReference(a))
 
- 
填充A的属性 - 发现A依赖B,触发B的创建
- 此时A仍处于半成品状态(未完成属性注入)
 
- 
创建B实例 - 实例化B,将B的ObjectFactory存入三级缓存
- 填充B属性时发现依赖A
 
- 实例化B,将B的
- 
解决依赖闭环 - B从三级缓存获取A的ObjectFactory
- 执行getEarlyBeanReference()生成A的早期引用(可能是代理对象)
- 将A从三级缓存移除,存入二级缓存:earlySingletonObjects.put("a", proxyA)
 
- B从三级缓存获取A的
- 
完成初始化 - B获得A的代理对象,完成属性注入→B初始化完成→存入一级缓存
- A获得B的完整实例,完成属性注入→A初始化完成→存入一级缓存
 
创建A实例 存入三级缓存 填充属性需B 创建B实例 填充属性需A 从三级缓存取A工厂 生成A代理存入二级缓存 B完成初始化 A完成初始化
- 三级缓存的核心作用
| 缓存级别 | 存储内容 | 核心目的 | 
|---|---|---|
| 一级缓存 | 完整Bean( singletonObjects) | 提供最终可用的Bean | 
| 二级缓存 | 半成品Bean( earlySingletonObjects) | 暂存早期暴露的对象 | 
| 三级缓存 | Bean工厂 ( ObjectFactory) | 动态创建代理对象 | 
关键设计亮点:
- 三级缓存通过ObjectFactory实现延迟处理,在需要注入时才执行AOP代理逻辑
- 避免直接暴露原始对象,确保注入的是最终代理对象(如@Transactional生效)
- 应用限制
| 依赖类型 | 是否支持 | 原因 | 
|---|---|---|
| Setter/字段注入 | ✅ 支持 | 可提前暴露半成品Bean | 
| 构造器注入 | ❌ 不支持 | 实例化前无法暴露引用 | 
| 原型(Prototype)Bean | ❌ 不支持 | Spring不缓存原型Bean | 
- 
典型案例分析 
 场景 :AService需注入BService,BService需注入AService(二者都有@Async代理)
 解决:
- 
AService实例化后,存入三级缓存(含生成代理的 ObjectFactory)
- 
BService创建时通过 ObjectFactory.getObject()获取A的代理对象
- 
避免直接注入原始对象导致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的三级缓存机制很强大,但也有其局限性:
- 仅适用于单例Bean:原型(prototype)作用域的Bean无法使用三级缓存解决循环依赖。
- 不支持构造器循环依赖 :如果循环依赖是通过构造器注入 (Constructor Injection)方式发生的,三级缓存也无法解决。因为Spring必须通过构造器创建对象实例,在实例化之前无法提前暴露引用,会直接抛出BeanCurrentlyInCreationException异常。
- 设计警示 :虽然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 为例)
- 
创建 Bean A - 实例化 A:调用构造函数生成原始对象。
- 暴露早期引用 :将 ObjectFactory存入三级缓存(singletonFactories),用于后续生成早期引用(可能是代理对象)。
- 依赖注入 B:发现 A 依赖 B,触发 B 的创建流程。
 
- 
创建 Bean B - 实例化 B:生成原始对象。
- 暴露早期引用 :将 B 的 ObjectFactory存入三级缓存。
- 依赖注入 A:发现 B 依赖 A,尝试从缓存获取 A 的实例。
 
- 
解决循环依赖 - 从三级缓存获取 A 的工厂 :调用 getObject()生成 A 的早期引用(可能为代理对象)。
- 存入二级缓存 :将 A 的早期引用移至 earlySingletonObjects,供 B 注入。
- 完成 B 的初始化:注入 A 的早期引用后,B 完成初始化并存入一级缓存。
 
- 从三级缓存获取 A 的工厂 :调用 
- 
完成 A 的初始化 - 注入 B 的最终实例:从一级缓存获取已完成的 B,完成 A 的依赖注入。
- A 存入一级缓存:A 的初始化完成后,移出二级缓存,最终存入一级缓存。
 
三、三级缓存设计的核心意图
- 
解决循环依赖 - 通过提前暴露未完全初始化的 Bean(二级缓存),允许依赖链中的其他 Bean 获取引用,避免死锁。
 
- 
支持 AOP 代理 - 三级缓存存储 ObjectFactory,在生成早期引用时调用getEarlyBeanReference(),确保代理对象的一致性。例如,若 A 被代理,B 注入的始终是同一代理实例。
 
- 三级缓存存储 
- 
并发控制与性能优化 - 双重检查锁 :在 getSingleton()方法中,首次创建 Bean 时加锁,后续直接读取缓存,减少锁竞争。
- 延迟初始化:三级缓存通过工厂模式延迟生成早期引用,避免不必要的对象创建。
 
- 双重检查锁 :在 
四、关键代码逻辑(简化版)
            
            
              java
              
              
            
          
          // AbstractAutowireCapableBeanFactory#doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
    // 1. 实例化 Bean
    Object 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,也就是我们常说的"三级缓存":
- 
一级缓存: singletonObjects- 类型: ConcurrentHashMap<String, Object>
- 存放内容: 存放已经完全初始化好的、成熟的单例 Bean。
- 作用: 这是最主要的缓存。我们通过 ApplicationContext.getBean()方法最终获取到的就是这里的 Bean。
 
- 类型: 
- 
二级缓存: earlySingletonObjects- 类型: HashMap<String, Object>
- 存放内容: 存放早期的、未完全初始化的 Bean 实例(已经实例化,但属性还未填充)。
- 作用: 它是一级缓存的临时替补。当一个早期对象被其他 Bean 依赖过后,就会被放在这里,避免再次创建代理对象的开销。
 
- 类型: 
- 
三级缓存: singletonFactories- 类型: HashMap<String, ObjectFactory<?>>
- 存放内容: 存放的是Bean 工厂对象(ObjectFactory) ,而不是 Bean 实例本身。这个工厂可以返回一个目标 Bean 的早期引用(可能是原始对象,也可能是代理对象)。
- 作用: 这是解决循环依赖和 AOP 代理问题的关键。它通过一个工厂来延迟决定最终返回的对象,从而能够智能地处理是否需要提前创建 AOP 代理。
 
- 类型: 
3. 解决循环依赖的完整流程(核心)
让我们以两个 Bean:A 和 B 相互依赖为例(A 中有 B,B 中有 A)。
- 
开始创建 A - Spring 调用 A 的构造器,实例化一个"原始对象"。
- 随后,Spring 将创建 A 的 ObjectFactory工厂对象,并放入三级缓存 (singletonFactories) 中。
 
- 
为 A 填充属性(Populate) - Spring 发现 A 依赖 B,于是尝试去获取 Bean B。
 
- 
开始创建 B - Spring 调用 B 的构造器,实例化一个"原始对象"。
- 随后,Spring 将创建 B 的 ObjectFactory工厂对象,并放入三级缓存 (singletonFactories) 中。
 
- 
为 B 填充属性(Populate) - Spring 发现 B 依赖 A,于是尝试去获取 Bean A。
 
- 
获取 A(关键步骤!) - Spring 首先去一级缓存 (singletonObjects) 找 A,没有找到(A 还没创建完)。
- 然后去二级缓存 (earlySingletonObjects) 找 A,也没有找到(A 还没被依赖过)。
- 最后去三级缓存 (singletonFactories) 找,成功找到了 A 的ObjectFactory。
- 调用 ObjectFactory.getObject()方法。- 如果 A 是一个普通 Bean,这个方法直接返回 A 的原始对象。
- 如果 A 需要被 AOP 代理 ,这个方法会提前触发 AOP 逻辑,生成一个代理对象并返回。
 
- 将这个从三级缓存中得到的对象(可能是原始对象,也可能是代理对象)放入二级缓存 (earlySingletonObjects) 中,同时从三级缓存中移除 对应的ObjectFactory。
- 最后,将这个早期引用注入给 Bean B。
 
- Spring 首先去一级缓存 (
- 
完成 B 的创建 - B 注入 A 成功后,继续完成 B 的其他生命周期步骤(初始化等)。
- B 创建完毕,被放入一级缓存 (singletonObjects),并从二、三级缓存中清除。
 
- 
回到 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 循环依赖问题的关键设计,以下是对其原理及相关内容的详细介绍:
一、三级缓存的结构与作用
- 
一级缓存 singletonObjects- 功能 : 存储已完全初始化并可用的单例 Bean 实例[1][2][4]。
- 特点 : 其中的 Bean 已完成所有属性注入和非惰性初始化操作,可直接返回给请求者使用[1][2][4]。
 
- 
二级缓存 earlySingletonObjects- 功能 : 存放早期暴露的 Bean 引用,这些对象已完成实例化但尚未完成属性注入或初始化[1][2][4]。
- 作用 : 允许其他 Bean 在创建过程中引用尚未完全初始化的 Bean,从而解决循环依赖问题[1][2][4]。
 
- 
三级缓存 singletonFactories- 功能 : 存储可生成 Bean 实例的工厂对象(ObjectFactory),而非直接存储 Bean 实例[1][2][4]。
- 核心作用 : 应对 AOP 代理场景。若 Bean 需要被代理(如通过 SmartInstantiationAwareBeanPostProcessor),则通过工厂动态生成代理对象而非原始对象[1][5]。
 
- 功能 : 存储可生成 Bean 实例的工厂对象(
二、三级缓存解决循环依赖的流程
- 
首次创建 Bean A - Spring 实例化 Bean A 后,将其封装为 ObjectFactory并存入三级缓存singletonFactories[1][5]。此时暂不放入一/二级缓存。
 
- Spring 实例化 Bean A 后,将其封装为 
- 
处理 Bean A 的依赖 Bean B - 当尝试注入 Bean B 时,发现其尚未创建,于是开始创建 Bean B。同样地将Bean B的 ObjectFactory存入三级缓存。
 
- 当尝试注入 Bean B 时,发现其尚未创建,于是开始创建 Bean B。同样地将Bean B的 
- 
检测到循环依赖 - 当创建 Bean B 的过程中试图注入 Bean A 时,从三级缓存中获取 Bean A 的 ObjectFactory,调用其getObject()方法生成早期引用[1][5]。
 
- 当创建 Bean B 的过程中试图注入 Bean A 时,从三级缓存中获取 Bean A 的 
- 
升级缓存层级 - 将 Bean A 的早期引用从三级缓存移至二级缓存 earlySingletonObjects,供 Bean B 完成属性注入[1][5]。
 
- 将 Bean A 的早期引用从三级缓存移至二级缓存 
- 
完成初始化并最终放入一级缓存 - Bean B 完成属性注入后,将其完整实例放入一级缓存 singletonObjects[1][5]。
- 随后继续完成 Bean A 的初始化,最终也将 Bean A 放入一级缓存。
 
- Bean B 完成属性注入后,将其完整实例放入一级缓存 
三、为何需要三级缓存而非二级?
- 
支持 AOP 代理 :若仅用二级缓存(直接存储未初始化完成的 Bean),则无法区分是否需要代理。三级缓存通过 ObjectFactory可在获取 Bean 时动态判断是否需要生成代理对象[1][5]。
- 
延迟代理对象的创建 :避免了在 Bean 生命周期早期错误地生成代理对象,确保 AOP 逻辑仅在必要时执行[1][5]。 
- 
线程安全与性能优化 :三级缓存通过分层设计和同步块控制,减少了并发场景下的锁竞争,提升了性能[5]。 
四、关键前提条件
- 
单例模式 :循环依赖的两个 Bean 必须都是单例的[3][4]。 
- 
非构造函数注入 :构造函数注入会导致实例化阶段陷入死循环,因为构造函数要求所有依赖立即可用[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 时,会经历以下流程:
- 
创建 Bean 实例(newInstance) - 调用构造方法创建一个原始对象(未注入属性、未初始化)。
 
- 
将 Bean 工厂放入三级缓存中 - 将一个 ObjectFactory放入三级缓存singletonFactories,用于后续获取代理对象。
 
- 将一个 
- 
填充属性(populateBean) - 如果依赖的其他 Bean 还未创建,会触发它们的创建流程,可能形成循环依赖。
 
- 
提前暴露 Bean(放入二级缓存) - 从三级缓存中获取 Bean 工厂,创建代理对象(如果有 AOP 需要),并将其移动到二级缓存。
 
- 
完成初始化(initializeBean) - 注入属性、调用初始化方法(如 init-method、@PostConstruct)。
 
- 
将 Bean 放入一级缓存 - 完全初始化好的 Bean 被放入一级缓存 singletonObjects,供其他 Bean 使用。
 
- 完全初始化好的 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的线程安全创建和高效复用。
一、三级缓存的组成与作用
- 
一级缓存(SingletonObjects) - 存储内容:完全初始化好的单例Bean。
- 作用:Bean在完成所有初始化步骤(如依赖注入、初始化方法调用、AOP代理等)后,会被放入一级缓存。后续获取Bean时直接从此缓存返回,避免重复创建。
- 特点 :线程安全,使用ConcurrentHashMap实现,保证高并发下的正确性。
 
- 
二级缓存(EarlySingletonObjects) - 存储内容:已实例化但未完全初始化的Bean(半成品Bean)。
- 作用:在Bean初始化过程中,若其他Bean依赖它,Spring会先将半成品Bean放入二级缓存,供依赖方提前使用。
- 特点:解决循环依赖的关键,允许Bean在未完全初始化时被引用,但避免重复创建。
 
- 
三级缓存(SingletonFactories) - 存储内容 :Bean的ObjectFactory对象(通常是一个Lambda表达式)。
- 作用:当Bean需要被代理(如AOP场景)时,三级缓存存储的是生成代理对象的工厂。通过工厂可以动态决定返回原始Bean还是代理Bean,保证全局唯一性。
- 特点:解决AOP代理与循环依赖的兼容问题,确保代理对象在循环依赖中也能正确生成。
 
- 存储内容 :Bean的
二、三级缓存的工作流程
以循环依赖场景(A依赖B,B依赖A)为例,说明三级缓存的协作过程:
- 
创建Bean A - Spring先检查一级缓存,未找到Bean A。
- 创建Bean A的实例(未注入依赖),将其对应的ObjectFactory放入三级缓存。
- 开始填充Bean A的属性,发现依赖Bean B。
 
- 
创建Bean B - 检查一级缓存,未找到Bean B。
- 创建Bean B的实例,将其ObjectFactory放入三级缓存。
- 开始填充Bean B的属性,发现依赖Bean A。
 
- 
解决Bean A的循环依赖 - Spring从三级缓存获取Bean A的ObjectFactory,调用getObject()方法生成Bean A的早期引用(可能是代理对象)。
- 将Bean A的早期引用从三级缓存移除,并放入二级缓存。
- Bean B完成属性注入(使用二级缓存中的Bean A早期引用),继续初始化。
 
- Spring从三级缓存获取Bean A的
- 
完成Bean B的初始化 - Bean B完成所有初始化步骤后,被放入一级缓存。
- 从二级缓存中移除Bean A的早期引用(若存在)。
 
- 
完成Bean A的初始化 - Spring继续初始化Bean A,使用一级缓存中的Bean B完成属性注入。
- Bean A完成所有初始化步骤后,被放入一级缓存。
 
三、三级缓存的核心优势
- 
解决循环依赖 通过提前暴露半成品Bean(二级缓存)和动态生成代理对象(三级缓存),避免循环依赖导致的无限递归或死锁。 
- 
优化性能 - 减少重复创建:已初始化的Bean直接从一级缓存返回,避免重复实例化。
- 懒加载支持:二级缓存实现Bean的按需初始化,降低启动时间。
 
- 
兼容AOP代理 三级缓存的 ObjectFactory机制确保代理对象在循环依赖中也能正确生成,解决原始Bean与代理Bean的冲突问题。
- 
线程安全保障 一级缓存使用 ConcurrentHashMap,二级和三级缓存通过同步块(synchronized)保证多线程环境下的正确性。
四、三级缓存的适用场景
- 单例Bean的循环依赖 :仅对作用域为singleton的Bean有效,原型(prototype)Bean无法使用三级缓存。
- AOP代理场景:当Bean需要被代理时,三级缓存的工厂机制确保代理对象在循环依赖中也能正确生成。
- 高并发环境:通过缓存机制减少锁竞争,提升Bean创建效率。
五、源码解析关键方法
- 
getSingleton(String beanName, boolean allowEarlyReference)- 核心逻辑:按一级→二级→三级缓存的顺序查找Bean。
- 若在三级缓存找到,调用ObjectFactory.getObject()生成早期引用,移入二级缓存并删除三级缓存条目。
 
- 
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)- 将Bean的ObjectFactory放入三级缓存,用于后续循环依赖的解决。
 
- 将Bean的
- 
doGetBean()与createBean()- 控制Bean的创建流程,包括依赖注入、初始化、缓存操作等。
 
🤔 参考 15
Spring的三级缓存机制是其解决循环依赖问题的核心设计,主要应用于单例(Singleton)Bean的创建过程中。这个机制通过三个Map(通常称为"三级缓存")来实现,确保在复杂的依赖注入场景下,Bean能够被正确、高效地创建和初始化。
以下是三级缓存的具体原理和作用:
1. 三级缓存的定义
Spring的DefaultSingletonBeanRegistry类中定义了三个Map,它们共同构成了三级缓存:
- 
一级缓存 ( singletonObjects):- 类型 : ConcurrentHashMap<String, Object>
- 作用 : 存放完全初始化好 的单例Bean实例。这些Bean已经完成了实例化、属性填充(依赖注入)和初始化方法(如@PostConstruct、InitializingBean)的调用。
- 特点: 这是最终的、可供使用的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。
- 
开始创建 AService:- Spring发现需要创建AService,首先检查一级缓存singletonObjects,没有找到。
- 然后检查二级缓存earlySingletonObjects,也没有找到。
- 接着检查三级缓存singletonFactories,同样没有。
- 于是开始创建AService。
 
- Spring发现需要创建
- 
暴露 AService的早期引用:- AService通过构造函数实例化完成(此时- AService对象已存在,但属性还未注入)。
- Spring将一个ObjectFactory(工厂)放入三级缓存singletonFactories中。这个工厂的作用是:当被调用时,可以返回AService的早期引用。
- 关键点 : 此时AService的早期引用尚未真正创建,只是准备好了创建它的"方法"。
 
- 
注入依赖 - 创建 BService:- AService需要注入- BService,于是Spring开始创建- BService。
- BService的创建流程类似,实例化完成后,也会将其- ObjectFactory放入三级缓存。
- BService需要注入- AService。
 
- 
解决循环依赖 - 获取 AService的早期引用:- 在为BService注入AService时,Spring再次查找AService。
- 一级、二级缓存都没有,但在三级缓存 中找到了AService的ObjectFactory。
- Spring调用这个ObjectFactory的getObject()方法。
- getObject()方法内部会调用- getEarlyBeanReference()。这一步至关重要 :- 如果AService需要被AOP代理(例如有@Transactional注解),那么getEarlyBeanReference()会在这里创建代理对象。
- 如果不需要代理,则直接返回原始的AService实例。
 
- 如果
- 将得到的早期引用(可能是原始对象,也可能是代理对象)放入二级缓存 earlySingletonObjects。
- 同时,从三级缓存中移除 AService的ObjectFactory。这保证了早期引用只会被创建一次。
- 将这个早期引用注入到BService中。
 
- 在为
- 
完成 BService的创建:- BService完成属性填充和初始化,成为一个完整的Bean,放入一级缓存- singletonObjects。
- 从二级和三级缓存中移除BService的相关条目。
 
- 
完成 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 什么是循环依赖
            
            
              java
              
              
            
          
          // 示例:两个 Bean 相互依赖
@Service
public class UserService {
    @Autowired
    private OrderService orderService;
}
@Service
public class OrderService {
    @Autowired 
    private UserService userService;  // 循环依赖
}1.2 循环依赖的类型
- 构造器循环依赖:无法解决
- Setter/字段循环依赖:可以通过三级缓存解决
- 原型 Bean 循环依赖:无法解决
2. 三级缓存机制
2.1 三级缓存定义
在 DefaultSingletonBeanRegistry 中:
            
            
              java
              
              
            
          
          public class DefaultSingletonBeanRegistry {
    // 一级缓存:完整的单例 Bean
    private 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 核心解决算法
            
            
              java
              
              
            
          
          // 获取 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. 从三级缓存获取 ObjectFactory
                ObjectFactory<?> 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 详细解决步骤
以 UserService 和 OrderService 循环依赖为例:
            
            
              java
              
              
            
          
          // 步骤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
    - 一级缓存:无
    - 二级缓存:无
    - 三级缓存:找到 UserService 的 ObjectFactory
    - 调用 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 生命周期与缓存
            
            
              java
              
              
            
          
          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 三级缓存的添加
            
            
              java
              
              
            
          
          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 代理对象的创建时机
            
            
              java
              
              
            
          
          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 代理示例
            
            
              java
              
              
            
          
          @Service
public class UserService {
    @Autowired
    private OrderService orderService;
    
    @Transactional  // 需要 AOP 代理
    public void updateUser() {
        // 事务方法
    }
}
@Service  
public class OrderService {
    @Autowired
    private UserService userService;  // 这里注入的应该是代理对象
}处理流程:
- UserService实例化后,三级缓存中的- ObjectFactory会检查是否需要 AOP 代理
- 由于有 @Transactional,getEarlyBeanReference返回代理对象
- OrderService注入的是- UserService的代理对象
- 保证事务功能正常工作
6. 无法解决的循环依赖情况
6.1 构造器循环依赖
            
            
              java
              
              
            
          
          @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 循环依赖
            
            
              java
              
              
            
          
          @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class UserService {
    @Autowired
    private OrderService orderService;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service  
public class OrderService {
    @Autowired
    private UserService userService;
}原因:原型 Bean 每次都会创建新实例,Spring 不支持原型 Bean 的循环依赖
7. 解决方案与最佳实践
7.1 使用 @Lazy 注解
            
            
              java
              
              
            
          
          @Service
public class UserService {
    @Lazy  // 延迟注入,打破循环依赖
    @Autowired
    private OrderService orderService;
}
@Service
public class OrderService {
    @Autowired
    private UserService userService;  // 正常注入
}7.2 使用 Setter 注入
            
            
              java
              
              
            
          
          @Service
public class UserService {
    private OrderService orderService;
    
    // Setter 注入
    @Autowired
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}7.3 使用 ApplicationContext
            
            
              java
              
              
            
          
          @Service
public class UserService implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    public void someMethod() {
        // 需要时再获取 OrderService
        OrderService orderService = applicationContext.getBean(OrderService.class);
    }
}7.4 代码重构
            
            
              java
              
              
            
          
          // 方案1:提取公共逻辑到第三个类
@Service
public class CommonService {
    // 公共逻辑
}
@Service
public class UserService {
    @Autowired
    private CommonService commonService;
}
@Service
public class OrderService {
    @Autowired
    private CommonService commonService;
}
// 方案2:使用接口分离
public interface UserOperation {
    void userOperation();
}
public interface OrderOperation {
    void orderOperation();  
}
@Service
public class UserService implements UserOperation {
    @Autowired
    private OrderOperation orderOperation;
}
@Service
public class OrderService implements OrderOperation {
    @Autowired
    private UserOperation userOperation;
}8. 调试与问题排查
8.1 启用循环依赖日志
            
            
              properties
              
              
            
          
           ##########  application.properties
logging.level.org.springframework.beans=DEBUG
logging.level.org.springframework.context=DEBUG8.2 自定义循环依赖检测
            
            
              java
              
              
            
          
          @Component
public class CircularDependencyChecker implements ApplicationRunner {
    
    @Autowired
    private ConfigurableListableBeanFactory beanFactory;
    
    @Override
    public 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 查看缓存状态
            
            
              java
              
              
            
          
          @Component
public class CacheStatusLogger implements ApplicationRunner {
    
    @Autowired
    private AbstractApplicationContext context;
    
    @Override
    public 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 相关配置属性
            
            
              bash
              
              
            
          
           ##########  application.properties
 ##########  是否允许循环引用(默认 true)
spring.main.allow-circular-references=true
 ##########  是否允许 Bean 定义覆盖(默认 false)  
spring.main.allow-bean-definition-overriding=false
 ##########  懒初始化(可以帮助避免某些循环依赖)
spring.main.lazy-initialization=false9.2 禁用循环依赖支持
            
            
              java
              
              
            
          
          @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 等方法级别的代理
核心原理:
- 提前暴露:Bean 实例化后立即暴露到三级缓存
- 工厂模式:通过 ObjectFactory 延迟决定返回原始对象还是代理对象
- 缓存升级:从三级缓存 → 二级缓存 → 一级缓存
- AOP 支持:在早期引用阶段处理代理逻辑
最佳实践:
- 优先使用 Setter 注入而非构造器注入
- 使用 @Lazy注解打破循环依赖
- 合理设计代码结构,避免循环依赖
- 在必要时进行代码重构
理解 Spring 的循环依赖解决机制对于设计复杂的 Spring 应用、排查启动问题以及进行性能优化都具有重要意义。