2026/3/6 12:34:09
网站建设
项目流程
商业网站建设设计公司,中信建设有限责任公司企业资质,网站做一半能退吗,网站改版 htmlSpring 的三级缓存是解决单例Bean循环依赖的核心机制。理解三级缓存对于掌握Spring的Bean创建过程至关重要。一、三级缓存定义与作用三级缓存的含义// 在 DefaultSingletonBeanRegistry 中定义
public class DefaultSingletonBeanRegistry extends ... {// 一级缓存#xff1a…Spring 的三级缓存是解决单例Bean循环依赖的核心机制。理解三级缓存对于掌握Spring的Bean创建过程至关重要。一、三级缓存定义与作用三级缓存的含义// 在 DefaultSingletonBeanRegistry 中定义 public class DefaultSingletonBeanRegistry extends ... { // 一级缓存存放完全初始化好的Bean private final MapString, Object singletonObjects new ConcurrentHashMap(256); // 二级缓存存放早期暴露的Bean已实例化但未完全初始化 private final MapString, Object earlySingletonObjects new ConcurrentHashMap(16); // 三级缓存存放Bean工厂用于创建早期引用 private final MapString, ObjectFactory? singletonFactories new HashMap(16); }各级缓存的作用缓存级别名称存储内容作用一级缓存singletonObjects完全初始化好的单例Bean缓存最终可用的Bean二级缓存earlySingletonObjects早期Bean半成品解决循环依赖避免重复创建代理三级缓存singletonFactoriesObjectFactoryBean工厂创建早期引用支持AOP等扩展二、循环依赖场景分析场景一最简单的循环依赖Component public class A { Autowired private B b; } Component public class B { Autowired private A a; }场景二自我依赖少见但能说明问题Component public class SelfRefBean { Autowired private SelfRefBean self; }三、三级缓存解决循环依赖的完整流程步骤详解以A↔B循环依赖为例// 模拟三级缓存解决循环依赖的过程 public class ThreeLevelCacheDemo { public static void main(String[] args) { // 创建过程模拟 createBeanA(); } static void createBeanA() { System.out.println(1. 开始创建Bean A); // Step 1: 实例化A调用构造函数 Object a new A(); System.out.println(2. A实例化完成将A的ObjectFactory放入三级缓存); // 三级缓存singletonFactories.put(a, () - getEarlyBeanReference(a, a)); // Step 2: 属性填充发现需要B System.out.println(3. 开始填充A的属性发现需要B); // Step 3: 创建B createBeanB(); // Step 6: 完成A的初始化 System.out.println(9. B创建完成继续完成A的初始化); System.out.println(10. 将A从二级缓存移除放入一级缓存); // 一级缓存singletonObjects.put(a, a); // 二级缓存earlySingletonObjects.remove(a); } static void createBeanB() { System.out.println(4. 开始创建Bean B); // Step 3: 实例化B Object b new B(); System.out.println(5. B实例化完成将B的ObjectFactory放入三级缓存); // 三级缓存singletonFactories.put(b, () - getEarlyBeanReference(b, b)); // Step 4: 属性填充发现需要A System.out.println(6. 开始填充B的属性发现需要A); // Step 5: 获取A从三级缓存获取早期引用 System.out.println(7. 从三级缓存获取A的早期引用); // Object earlyA singletonFactories.get(a).getObject(); System.out.println(8. 将A放入二级缓存从三级缓存移除A的工厂); // 二级缓存earlySingletonObjects.put(a, earlyA); // 三级缓存singletonFactories.remove(a); // 将earlyA注入到B System.out.println(9. 将A的早期引用注入B完成B的初始化); System.out.println(10. 将B从二级缓存移除放入一级缓存); // 一级缓存singletonObjects.put(b, b); // 二级缓存earlySingletonObjects.remove(b); } }流程图解创建A → 实例化A → 将A工厂放入三级缓存 ↓ 填充A属性 → 需要B → 创建B ↓ 实例化B → 将B工厂放入三级缓存 ↓ 填充B属性 → 需要A → 从三级缓存获取A工厂 ↓ ↓ 创建A早期引用 ← 执行A工厂getObject() ↓ 将A早期引用放入二级缓存移除三级缓存中的A工厂 ↓ 将A早期引用注入B → 完成B初始化 ↓ 将B放入一级缓存 → 返回B ↓ 获取到B → 注入B到A → 完成A初始化 ↓ 将A放入一级缓存移除二级缓存中的A四、三级缓存源码深度解析1. 获取Bean的核心方法protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 1. 先从一级缓存获取 Object singletonObject this.singletonObjects.get(beanName); // 如果一级缓存没有且Bean正在创建中解决循环依赖 if (singletonObject null isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 2. 从二级缓存获取 singletonObject this.earlySingletonObjects.get(beanName); // 如果二级缓存没有且允许早期引用 if (singletonObject null allowEarlyReference) { // 3. 从三级缓存获取Bean工厂 ObjectFactory? singletonFactory this.singletonFactories.get(beanName); if (singletonFactory ! null) { // 通过工厂创建早期Bean singletonObject singletonFactory.getObject(); // 放入二级缓存 this.earlySingletonObjects.put(beanName, singletonObject); // 移除三级缓存中的工厂 this.singletonFactories.remove(beanName); } } } } return singletonObject; }2. Bean创建过程中的缓存操作protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) { // 1. 实例化Bean BeanWrapper instanceWrapper createBeanInstance(beanName, mbd, args); Object bean instanceWrapper.getWrappedInstance(); // 2. 判断是否支持早期暴露单例、允许循环引用 boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 3. 将Bean工厂添加到三级缓存 addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean)); } // 4. 属性填充可能触发循环依赖 populateBean(beanName, mbd, instanceWrapper); // 5. 初始化 Object exposedObject initializeBean(beanName, exposedObject, mbd); // 6. 处理早期引用 if (earlySingletonExposure) { // 从一级缓存获取检查是否已被其他Bean初始化过程修改 Object earlySingletonReference getSingleton(beanName, false); if (earlySingletonReference ! null) { // 如果exposedObject没有被增强使用早期引用 if (exposedObject bean) { exposedObject earlySingletonReference; } } } return exposedObject; } // 添加工厂到三级缓存 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); } } }3. 获取早期Bean引用支持AOPprotected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject bean; // 1. 如果Bean需要被后处理器增强如AOP if (!mbd.isSynthetic() hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp (SmartInstantiationAwareBeanPostProcessor) bp; // 2. 获取早期引用可能是代理对象 exposedObject ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }五、为什么需要三级缓存二级不够吗场景分析AOP代理的循环依赖Component public class A { Autowired private B b; public void doSomething() { System.out.println(A do something); } } Component public class B { Autowired private A a; // 这里期望注入的是A的代理对象而不是原始对象 public void test() { // 如果注入的是原始对象AOP增强会失效 a.doSomething(); } } Aspect Component public class LogAspect { Before(execution(* com.example.A.doSomething(..))) public void logBefore() { System.out.println(Log before method execution); } }三级缓存的必要性延迟代理创建三级缓存存储的是ObjectFactory可以延迟决定何时以及如何创建代理保证代理一致性确保所有Bean注入的是同一个代理实例避免重复创建代理如果没有三级缓存每次获取早期引用都可能创建新的代理如果只有二级缓存的问题// 假设只有二级缓存 public Object getSingleton(String beanName) { Object bean singletonObjects.get(beanName); if (bean null isSingletonCurrentlyInCreation(beanName)) { // 只有二级缓存直接创建早期引用 bean createEarlyBeanReference(beanName); earlySingletonObjects.put(beanName, bean); } return bean; } // 问题如果多个地方同时获取早期引用可能创建多个不同的代理实例 // 特别是当A需要被AOP增强时六、特殊场景处理1. 构造器循环依赖无法解决Component public class ConstructorA { private ConstructorB b; Autowired public ConstructorA(ConstructorB b) { // 构造器注入 this.b b; } } Component public class ConstructorB { private ConstructorA a; Autowired public ConstructorB(ConstructorA a) { // 构造器注入 this.a a; } } // 抛出 BeanCurrentlyInCreationException原因构造器注入时Bean还未实例化无法放入三级缓存。2. 原型Bean的循环依赖无法解决Component Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class PrototypeA { Autowired private PrototypeB b; } Component Scope(ConfigurableBeanFactory.SCOPE_PROTotype) public class PrototypeB { Autowired private PrototypeA a; } // 抛出 BeanCurrentlyInCreationException原因原型Bean不缓存每次都是新创建Spring不支持原型Bean的循环依赖。3. Async注解的循环依赖Component public class AsyncA { Autowired private AsyncB b; Async public void asyncMethod() { // 异步方法 } } Component public class AsyncB { Autowired private AsyncA a; // 这里注入的可能是原始对象而不是代理 }解决方法使用Lazy注解Component public class AsyncB { Lazy Autowired private AsyncA a; }七、三级缓存与AOP的协作代理创建时机// AbstractAutoProxyCreatorAOP核心类中的处理 public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey getCacheKey(bean.getClass(), beanName); // 将原始Bean和代理关系缓存起来 this.earlyProxyReferences.put(cacheKey, bean); // 创建代理 return wrapIfNecessary(bean, beanName, cacheKey); } // 后续初始化完成后检查 public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean ! null) { Object cacheKey getCacheKey(bean.getClass(), beanName); // 如果早期已经创建过代理直接返回早期代理 if (this.earlyProxyReferences.remove(cacheKey) ! bean) { // 否则检查是否需要创建代理 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }八、性能与线程安全考虑1. 缓存访问的同步// DefaultSingletonBeanRegistry 中的同步控制 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); } }2. 性能优化一级缓存使用ConcurrentHashMap支持高并发读二级缓存使用ConcurrentHashMap但实际访问需要加锁三级缓存使用HashMap因为只在创建Bean时访问且需要同步九、实际调试技巧1. 查看三级缓存状态SpringBootTest public class CacheDebugTest { Autowired private ApplicationContext applicationContext; Test public void debugThreeLevelCache() throws Exception { DefaultSingletonBeanRegistry registry (DefaultSingletonBeanRegistry) ((AbstractApplicationContext) applicationContext).getBeanFactory(); // 通过反射查看缓存内容 Field singletonObjectsField DefaultSingletonBeanRegistry.class .getDeclaredField(singletonObjects); singletonObjectsField.setAccessible(true); MapString, Object singletonObjects (MapString, Object) singletonObjectsField.get(registry); System.out.println(一级缓存大小: singletonObjects.size()); // 类似方式可以查看二级和三级缓存 } }2. 循环依赖调试配置# application.properties # 开启循环依赖调试日志 logging.level.org.springframework.beans.factory.supportDEBUG # 关闭Spring的循环依赖快速失败仅用于调试 spring.main.allow-circular-referencestrue十、最佳实践与注意事项1. 避免循环依赖优先使用构造器注入强制在编译期发现循环依赖代码重构提取公共逻辑到第三个类中使用Lazy注解延迟加载打破循环2. 设计建议// 不好的设计双向紧密耦合 Service public class OrderService { Autowired private UserService userService; } Service public class UserService { Autowired private OrderService orderService; } // 好的设计提取公共逻辑 Service public class OrderService { Autowired private CommonService commonService; } Service public class UserService { Autowired private CommonService commonService; } Service public class CommonService { // 公共业务逻辑 }3. 配置建议Configuration public class AppConfig { // 如果不使用AOP可以关闭循环引用支持提升性能 Bean public static BeanFactoryPostProcessor disableCircularReferences() { return beanFactory - { if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowCircularReferences(false); } }; } }总结Spring三级缓存的核心价值解决循环依赖通过提前暴露Bean引用支持AOP确保注入的是正确的代理对象保证单例唯一性避免重复创建Bean实例性能优化减少不必要的Bean创建理解三级缓存不仅有助于解决循环依赖问题更能深入理解Spring容器的设计哲学。在实际开发中虽然三级缓存解决了技术问题但良好的设计应该尽量避免循环依赖的出现。