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,它们互相依赖:

java 复制代码
class A {
    @Autowired
    private B b;
}

class B {
    @Autowired
    private 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 代理的正确创建时机。


✅ 图示(简化)

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

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

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 循环依赖解决示例

UserServiceOrderService 为例:

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;  // 这里需要注入代理对象
}

处理流程:

  1. UserService 实例化后,三级缓存中的 ObjectFactory 会检查是否需要 AOP 代理
  2. 如果需要代理,getEarlyBeanReference 返回代理对象
  3. OrderService 注入的是 UserService 的代理对象
  4. 保证事务等 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 避免循环依赖

最佳实践

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

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 三级缓存机制的核心要点:

  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 类中定义了三层缓存:

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

创建流程:

  1. 开始创建 A

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

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

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

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

    java 复制代码
    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 完成创建

    java 复制代码
    // B 完成属性注入和初始化
    // 将 B 放入一级缓存,清除二三级缓存
    addSingleton("b", b);
  7. 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 的三级缓存机制:

  1. 一级缓存:完整 Bean,可直接使用
  2. 二级缓存:早期 Bean,解决普通循环依赖
  3. 三级缓存: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;
}

创建过程详解

  1. 开始创建 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 的详细步骤:

  1. 实例化 A

    java 复制代码
    // 调用构造方法创建A实例
    instanceWrapper = createBeanInstance(beanName, mbd, args);
    Object bean = instanceWrapper.getWrappedInstance();
  2. 将 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);
            }
        }
    }
  3. 属性注入 - 发现依赖 B

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

  5. 实例化 B

  6. 将 B 的 ObjectFactory 放入三级缓存

  7. 属性注入 - 发现依赖 A

  8. 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;
}
  1. 完成创建过程
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("方法执行前日志");
    }
}

处理流程

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

三级缓存总结

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

设计思想

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

最佳实践

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

三级缓存机制是 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完整Bean

5. 源码关键方法解析

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;  // 这里注入的应该是代理对象
}

处理过程

  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 什么是循环依赖

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: 正在创建的 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,并升级到二级缓存。
    java 复制代码
    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. 三级缓存的定义
java 复制代码
// Spring容器中的三级缓存
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存:完整Bean
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 二级缓存:半成品Bean
Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(); // 三级缓存:Bean工厂
  1. 解决循环依赖的流程(以A→B→A为例)

  2. 创建A实例

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

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

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

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

    • B获得A的代理对象,完成属性注入→B初始化完成→存入一级缓存
    • A获得B的完整实例,完成属性注入→A初始化完成→存入一级缓存

创建A实例 存入三级缓存 填充属性需B 创建B实例 填充属性需A 从三级缓存取A工厂 生成A代理存入二级缓存 B完成初始化 A完成初始化

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

关键设计亮点:

  • 三级缓存通过ObjectFactory实现延迟处理,在需要注入时才执行AOP代理逻辑
  • 避免直接暴露原始对象,确保注入的是最终代理对象(如@Transactional生效)
  1. 应用限制
依赖类型 是否支持 原因
Setter/字段注入 ✅ 支持 可提前暴露半成品Bean
构造器注入 ❌ 不支持 实例化前无法暴露引用
原型(Prototype)Bean ❌ 不支持 Spring不缓存原型Bean
  1. 典型案例分析
    场景 :AService需注入BService,BService需注入AService(二者都有@Async代理)
    解决

  2. AService实例化后,存入三级缓存(含生成代理的ObjectFactory

  3. BService创建时通过ObjectFactory.getObject()获取A的代理对象

  4. 避免直接注入原始对象导致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 时加锁,后续直接读取缓存,减少锁竞争。
    • 延迟初始化:三级缓存通过工厂模式延迟生成早期引用,避免不必要的对象创建。

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

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,也就是我们常说的"三级缓存":

  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 什么是循环依赖

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 详细解决步骤

UserServiceOrderService 循环依赖为例:

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;  // 这里注入的应该是代理对象
}

处理流程

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

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=DEBUG

8.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=false

9.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 等方法级别的代理

核心原理:

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

最佳实践:

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

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







Spring的三级缓存原理 笔记251008

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

Spring的 三级缓存 与 AOP 笔记251009

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

相关推荐
jun71182 小时前
msi mesi moesi cpu缓存一致性
缓存
DKPT5 小时前
JVM栈溢出和堆溢出哪个先满?
java·开发语言·jvm·笔记·学习
bnsarocket11 小时前
Verilog和FPGA的自学笔记1——FPGA
笔记·fpga开发·verilog·自学
今天只学一颗糖11 小时前
Linux学习笔记--insmod 命令
linux·笔记·学习
丰锋ff11 小时前
2016 年真题配套词汇单词笔记(考研真相)
笔记
Le1Yu12 小时前
2025-10-7学习笔记
java·笔记·学习
popoxf12 小时前
spring容器启动流程(反射视角)
java·后端·spring
谷哥的小弟13 小时前
Spring Framework源码解析——ApplicationContextAware
spring·源码
Zwb29979213 小时前
Day 24 - 文件、目录与路径 - Python学习笔记
笔记·python·学习