【 手撕J*a源码专栏 】深入理解Spring三级缓存:从源码到实践,彻底解决循环依赖


示例代码地址:[github](https://github.com/whltaoin/blog-code-collection) **前言**:\u003e 本文将从spring三级缓存的设计原理出发,通过手写实现和详细分析,带你彻底理解spring如何优雅地解决bean循环依赖问题,同时提供常见面试题解析。\u003e

## 一、什么是循环依赖?为什么需要解决它?### 1.1 循环依赖的概念循环依赖是指在应用程序中,多个Bean之间互相依赖,形成一个闭环。最常见的场景如:

```j*a// A依赖B@Servicepublic class ServiceA { @Autowired private ServiceB serviceB;}

// B依赖A@Servicepublic class ServiceB { @Autowired private ServiceA serviceA;}```

如果没有特殊处理,这种依赖关系会导致无限递归创建Bean,最终导致栈溢出错误。

### 1.2 循环依赖的三种情况在Spring中,循环依赖主要有三种情况:

1. **构造器循环依赖**:通过构造函数注入形成的循环依赖(Spring无法解决)2. **setter方法循环依赖**:通过setter方法注入形成的循环依赖(Spring可以解决)3. **字段注入循环依赖**:通过@Autowired注解直接注入字段(Spring可以解决)

## 二、Spring三级缓存的设计思路### 2.1 为什么需要三级缓存?想象一下这个场景:

+ 我们需要创建Bean A,但它依赖于Bean B+ 我们需要创建Bean B,但它又依赖于Bean A

如果我们能在Bean完全初始化之前,就将它的\"早期引用\"暴露出去,让其他Bean能够引用它,那么就能打破这个循环。

Spring的三级缓存正是基于这个思路设计的。

### 2.2 三级缓存的定义Spring使用三个不同级别的缓存来管理Bean的创建过程:

| 缓存级别 | 名称 | 用途 | 存储内容 || --- | --- | --- | --- || 一级缓存 | singletonObjects | 存储完全初始化好的单例Bean | 已完成所有属性注入和初始化的最终Bean实例 || 二级缓存 | earlySingletonObjects | 存储早期暴露的Bean引用 | 已实例化但尚未完成属性注入的Bean实例 || 三级缓存 | singletonFactories | 存储Bean工厂对象 | 用于创建Bean早期引用的ObjectFactory |

### 2.3 核心设计思想1. **提前暴露引用**:在Bean实例化后、属性注入前,就将其引用暴露出去2. **延迟代理创建**:通过工厂模式,在真正需要时才创建代理对象3. **缓存升级机制**:随着Bean初始化的推进,引用会在不同级别缓存间移动

## 三、手撕Spring三级缓存源码接下来,让我们手动实现一个简化版的Spring三级缓存机制,看看它是如何解决循环依赖的。

### 3.1 定义对象工厂接口首先,我们需要一个对象工厂接口,用于创建Bean的早期引用:

```j*a/** * 对象工厂接口,用于创建Bean的早期引用 */public interface CustomObjectFactory\u003cT\u003e { /** * 获取Bean实例 * @return Bean实例 */ T getObject();}```

这是Spring中`ObjectFactory`的简化版,它的作用是**在需要时创建或获取对象**,支持延迟初始化。

### 3.2 实现三级缓存核心类下面是我们手动实现的三级缓存核心类,模拟Spring的`DefaultSingletonBeanRegistry`:

```j*a/** * 自定义单例Bean注册表,实现Spring的三级缓存机制 */public class CustomSingletonBeanRegistry { // 一级缓存:存储完全初始化好的单例Bean private final Map\u003cString, Object\u003e singletonObjects = new ConcurrentHashMap\u003c\u003e(256); // 二级缓存:存储早期曝光的Bean实例(尚未完成属性注入) private final Map\u003cString, Object\u003e earlySingletonObjects = new HashMap\u003c\u003e(16); // 三级缓存:存储Bean工厂对象,用于生成Bean的早期引用 private final Map\u003cString, CustomObjectFactory\u003c?\u003e\u003e singletonFactories = new HashMap\u003c\u003e(16); // 正在创建中的Bean集合 private final Set\u003cString\u003e singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap\u003c\u003e(16)); // 已注册的Bean名称集合 private final Set\u003cString\u003e registeredSingletons = Collections.newSetFromMap(new ConcurrentHashMap\u003c\u003e(256)); // 排除检查的Bean名称集合 private final Set\u003cString\u003e inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap\u003c\u003e(16)); /** * 获取单例Bean(核心方法) */ @SuppressWarnings(\"unchecked\") public Object getSingleton(String beanName) { // 1. 先从一级缓存获取 Object singletonObject = this.singletonObjects.get(beanName); // 2. 如果一级缓存中不存在,且当前Bean正在创建中 if (singletonObject == null \u0026\u0026 isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 3. 从二级缓存获取早期引用 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { // 4. 从三级缓存获取工厂对象 CustomObjectFactory\u003c?\u003e singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 5. 通过工厂获取早期Bean引用 singletonObject = singletonFactory.getObject(); // 6. 将早期引用放入二级缓存 this.earlySingletonObjects.put(beanName, singletonObject); // 7. 从三级缓存移除工厂对象 this.singletonFactories.remove(beanName); } } } } return singletonObject; } /** * 注册单例Bean(完全初始化后的Bean) */ public void registerSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 放入一级缓存 this.singletonObjects.put(beanName, singletonObject); // 从二级缓存移除 this.earlySingletonObjects.remove(beanName); // 从三级缓存移除 this.singletonFactories.remove(beanName); // 注册Bean名称 this.registeredSingletons.add(beanName); } } /** * 添加单例工厂(用于创建早期引用) */ public void addSingletonFactory(String beanName, CustomObjectFactory\u003c?\u003e singletonFactory) { synchronized (this.singletonObjects) { // 只有当一级缓存中不存在时,才添加到三级缓存 if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); } } } /** * 标记Bean为正在创建中 */ public void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) \u0026\u0026 !this.singletonsCurrentlyInCreation.add(beanName)) { throw new RuntimeException(\"Bean with name '\" + beanName + \"' is currently in creation: \" + \"Is there an unresolvable circular reference?\"); } } /** * 标记Bean创建完成 */ public void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) \u0026\u0026 !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new RuntimeException(\"Singleton '\" + beanName + \"' isn't currently in creation\"); } } /** * 检查Bean是否正在创建中 */ public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }}```

这个类实现了Spring三级缓存的核心逻辑,特别是`getSingleton`方法,它定义了从缓存中获取Bean的优先级顺序。

### 3.3 实现Bean工厂接下来,我们实现一个简单的Bean工厂,用于创建和管理Bean:

```j*a/** * 自定义Bean工厂,用于创建和管理Bean */public class CustomBeanFactory { // 使用我们的自定义单例Bean注册表 private final CustomSingletonBeanRegistry singletonRegistry = new CustomSingletonBeanRegistry(); // 存储Bean定义的映射 private final Map\u003cString, BeanDefinition\u003c?\u003e\u003e beanDefinitions = new HashMap\u003c\u003e(); /** * 注册Bean定义 */ public \u003cT\u003e void registerBean(String beanName, Class\u003cT\u003e beanClass, String... dependencies) { BeanDefinition\u003cT\u003e definition = new BeanDefinition\u003c\u003e(beanClass, dependencies); beanDefinitions.put(beanName, definition); } /** * 获取Bean实例(核心方法) */ @SuppressWarnings(\"unchecked\") public \u003cT\u003e T getBean(String beanName) { // 1. 先尝试从单例缓存中获取 Object bean = singletonRegistry.getSingleton(beanName); if (bean != null) { return (T) bean; } // 2. 如果缓存中没有,开始创建Bean BeanDefinition\u003cT\u003e definition = (BeanDefinition\u003cT\u003e) beanDefinitions.get(beanName); if (definition == null) { throw new RuntimeException(\"No bean named '\" + beanName + \"' *ailable\"); } try { // 3. 标记Bean为正在创建中 singletonRegistry.beforeSingletonCreation(beanName); // 4. 创建Bean实例 T instance = createBean(definition); // 5. 添加到三级缓存,用于解决循环依赖 singletonRegistry.addSingletonFactory(beanName, () -\u003e instance); // 6. 注入依赖 injectDependencies(instance, definition); // 7. 初始化Bean initializeBean(instance); // 8. 注册到单例缓存(一级缓存) singletonRegistry.registerSingleton(beanName, instance); return instance; } catch (Exception e) { throw new RuntimeException(\"Error creating bean with name '\" + beanName + \"': \" + e.getMessage(), e); } finally { // 9. 标记Bean创建完成 singletonRegistry.afterSingletonCreation(beanName); } } // 其他辅助方法... private \u003cT\u003e T createBean(BeanDefinition\u003cT\u003e definition) throws Exception { System.out.println(\"Creating bean instance for: \" + definition.getBeanClass().getSimpleName()); return definition.getBeanClass().getDeclaredConstructor().newInstance(); } private \u003cT\u003e void injectDependencies(T instance, BeanDefinition\u003cT\u003e definition) throws Exception { // 简化的依赖注入实现 // 实际Spring中会使用反射查找setter方法或字段 } private \u003cT\u003e void initializeBean(T instance) { System.out.println(\"Initializing bean: \" + instance.getClass().getSimpleName()); } /** * Bean定义内部类 */ private static class BeanDefinition\u003cT\u003e { private final Class\u003cT\u003e beanClass; private final String[] dependencies; public BeanDefinition(Class\u003cT\u003e beanClass, String[] dependencies) { this.beanClass = beanClass; this.dependencies = dependencies; } public Class\u003cT\u003e getBeanClass() { return beanClass; } public String[] getDependencies() { return dependencies; } }}```

这个Bean工厂模拟了Spring创建Bean的核心流程,包括实例化、属性注入和初始化。

## 四、三级缓存解决循环依赖的完整流程现在,让我们通过一个具体的例子,详细说明三级缓存如何解决循环依赖问题。

### 4.1 创建循环依赖的示例Bean我们创建两个互相依赖的Bean类:

```j*a/** * 示例BeanA,与BeanB形成循环依赖 */public class BeanA { private BeanB beanB; public BeanA() { System.out.println(\"BeanA constructor called\"); } // Setter方法用于依赖注入 public void setBeanB(BeanB beanB) { this.beanB = beanB; System.out.println(\"BeanA injected with BeanB\"); } public String getMessage() { return \"Hello from BeanA\"; }}

/** * 示例BeanB,与BeanA形成循环依赖 */public class BeanB { private BeanA beanA; public BeanB() { System.out.println(\"BeanB constructor called\"); } // Setter方法用于依赖注入 public void setBeanA(BeanA beanA) { this.beanA = beanA; System.out.println(\"BeanB injected with BeanA\"); } public String getMessage() { return \"Hello from BeanB\"; }}```

### 4.2 循环依赖解决的详细流程下面是一个详细的流程图,展示了三级缓存如何解决循环依赖:

```plain┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ 创建BeanA │ │ 创建BeanB │ │ 完成初始化 │└─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ ▼ ▼ ▼┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ 1.标记创建中 │ │ 4.标记创建中 │ │ 12.BeanA完成│└─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ ▼ ▼ ▼┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ 2.实例化BeanA│ │ 5.实例化BeanB│ │ 13.放入一级 │└─────┬───────┘ └─────┬───────┘ └─────┬───────┘ │ │ │ ▼ ▼ │┌─────────────┐ ┌─────────────┐ ││ 3.放入三级缓存│─────▶7.需要BeanA │ │└─────┬───────┘ └─────┬───────┘ │ │ │ │ ▼ ▼ │┌─────────────┐ ┌─────────────┐ ││ 9.从三级获取│◀────┼8.查找BeanA │ │└─────┬───────┘ └─────┬───────┘ │ │ │ │ ▼ ▼ │┌─────────────┐ ┌─────────────┐ ││10.放入二级缓存│ │11.BeanB完成 │ │└─────┬───────┘ └─────┬───────┘ │ │ │ │ └───────────────────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ 放入一级缓存 │ │ └─────────────┘ │ │ │ └─────────────────────┘```

详细步骤说明:

1. **初始化BeanA**: - 标记BeanA为正在创建中 - 实例化BeanA(调用构造函数) - 将BeanA的工厂对象放入三级缓存 - BeanA需要注入BeanB,开始创建BeanB2. **初始化BeanB**: - 标记BeanB为正在创建中 - 实例化BeanB(调用构造函数) - 将BeanB的工厂对象放入三级缓存 - BeanB需要注入BeanA,触发从缓存获取BeanA3. **解决循环依赖**: - BeanB尝试注入BeanA时,从三级缓存获取BeanA的工厂 - 通过工厂获取BeanA的早期引用,放入二级缓存 - 将BeanA的早期引用注入到BeanB中 - BeanB完成属性注入和初始化,放入一级缓存 - 回到BeanA,注入已经完全初始化的BeanB - BeanA完成所有初始化,放入一级缓存

### 4.3 运行效果展示当我们运行以下测试代码:

```j*a// 创建自定义Bean工厂CustomBeanFactory beanFactory = new CustomBeanFactory();

// 注册Bean定义,声明循环依赖关系beanFactory.registerBean(\"beanA\", BeanA.class, \"beanB\");beanFactory.registerBean(\"beanB\", BeanB.class, \"beanA\");

// 获取BeanA,这将触发循环依赖的解决过程BeanA beanA = beanFactory.getBean(\"beanA\");```

我们会看到类似这样的输出:

```plainCreating bean instance for: BeanABeanA constructor calledCreating bean instance for: BeanBBeanB constructor calledBeanB injected with BeanAInitializing bean: BeanBBeanA injected with BeanBInitializing bean: BeanA```

这清晰地展示了三级缓存如何解决循环依赖的过程。

## 五、为什么需要三级缓存而不是两级?这是面试中的高频问题。很多人会问:既然二级缓存已经可以存储早期引用,为什么还需要三级缓存?

### 5.1 AOP代理的考虑**答案核心:三级缓存的关键作用是支持AOP代理。**

具体来说:

1. **延迟代理创建**:ObjectFactory允许在真正需要时才创建代理对象,而不是在Bean实例化后立即创建2. **条件代理**:只有当Bean被其他Bean引用且需要代理时,才会通过工厂创建代理对象3. **避免不必要的代理**:如果一个Bean没有被其他Bean循环依赖引用,就不会触发从三级缓存获取

### 5.2 举个例子说明假设我们有一个需要AOP代理的Bean:

+ **两级缓存方案**:无论是否有循环依赖,都需要在Bean实例化后立即创建代理对象,放入二级缓存+ **三级缓存方案**:只有当有循环依赖时,才会在真正需要引用时通过工厂创建代理对象

Ghiblio Ghiblio

专业AI吉卜力风格转换平台,将生活照变身吉卜力风格照

Ghiblio 157 查看详情 Ghiblio

这样,三级缓存避免了不必要的代理对象创建,提高了性能。

## 六、常见面试题解析### 6.1 Spring如何解决循环依赖?**答案**:Spring通过三级缓存机制解决循环依赖问题:

1. **一级缓存(singletonObjects)**:存储完全初始化好的Bean2. **二级缓存(earlySingletonObjects)**:存储早期暴露的Bean引用3. **三级缓存(singletonFactories)**:存储Bean工厂对象

当出现循环依赖时,Spring会在Bean实例化后但未完成属性注入前,将Bean的工厂对象放入三级缓存。当另一个Bean需要依赖该Bean时,会通过工厂获取早期引用,并将其升级到二级缓存,从而解决循环依赖问题。

### 6.2 构造器注入的循环依赖为什么无法解决?**答案**:构造器注入的循环依赖无法解决的原因是:在构造器注入的情况下,Bean在实例化阶段就需要依赖对象完全创建好。当A的构造器需要B,而B的构造器需要A时,就会陷入死循环。

Spring的三级缓存机制只能解决setter注入的循环依赖,因为setter注入允许先创建实例,再注入依赖。

### 6.3 Spring中singletonObjects、earlySingletonObjects和singletonFactories的区别?**答案**:

+ **singletonObjects**:一级缓存,存储完全初始化好的单例Bean,这些Bean已经完成了所有属性注入和初始化过程+ **earlySingletonObjects**:二级缓存,存储早期暴露的Bean引用,这些Bean已经实例化但尚未完成属性注入+ **singletonFactories**:三级缓存,存储Bean工厂对象,用于在需要时创建Bean的早期引用或代理对象

这三个缓存的优先级依次是:singletonObjects \u003e earlySingletonObjects \u003e singletonFactories

### 6.4 如果移除三级缓存,只用两级缓存,能解决循环依赖吗?**答案**:如果不考虑AOP代理,只用两级缓存也可以解决简单的循环依赖。但在有AOP代理的情况下,两级缓存无法正确处理代理对象的创建时机,可能导致获取到的不是最终的代理对象。

三级缓存通过ObjectFactory提供了更灵活的机制,可以在真正需要时才创建代理对象,这对于正确处理AOP代理至关重要。

## 八、手写与原生三级缓存对比测试与分析为了深入理解Spring三级缓存的工作原理,我们不仅分析了源码,还手动实现了一套简化版的三级缓存机制,并通过测试进行了对比。下面我们来看看两种实现的测试结果和对比分析。

### 8.1 测试模块概述我们创建了两个测试类,分别验证Spring原生三级缓存和自定义三级缓存的功能:

1. **SpringThreeLevelCacheTest**:测试Spring框架自带的三级缓存机制2. **CustomThreeLevelCacheTest**:测试我们手写的三级缓存实现

### 8.2 Spring原生三级缓存测试#### 8.2.1 测试类实现```j*a@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = SpringConfig.class)public class SpringThreeLevelCacheTest { @Autowired private ServiceA serviceA; @Autowired private ServiceB serviceB; @Test public void testCircularDependency() { System.out.println(\"\===== Spring三级缓存循环依赖测试 =====\"); // 验证ServiceA是否成功注入了ServiceB System.out.println(\"ServiceA调用结果: \" + serviceA.getInfo()); // 验证循环依赖是否成功解决 System.out.println(\"验证循环依赖是否解决:\"); System.out.println(\"- ServiceA的serviceB引用: \" + serviceB.getMessage()); // 打印两个对象的hashCode,确认是同一个实例 System.out.println(\"\对象引用验证:\"); System.out.println(\"- ServiceA实例: \" + serviceA); System.out.println(\"- ServiceB实例: \" + serviceB); System.out.println(\"\Spring三级缓存成功解决了循环依赖问题!\"); }}```

#### 8.2.2 被测试的服务类```j*a@Componentpublic class ServiceA { private ServiceB serviceB; public ServiceA() { System.out.println(\"ServiceA构造函数被调用\"); } @Autowired public void setServiceB(ServiceB serviceB) { System.out.println(\"ServiceA的setServiceB方法被调用\"); this.serviceB = serviceB; } public String getInfo() { return \"ServiceA调用ServiceB: \" + serviceB.getMessage(); }}

@Componentpublic class ServiceB { private ServiceA serviceA; public ServiceB() { System.out.println(\"ServiceB构造函数被调用\"); } @Autowired public void setServiceA(ServiceA serviceA) { System.out.println(\"ServiceB的setServiceA方法被调用\"); this.serviceA = serviceA; } public String getMessage() { return \"Hello from ServiceB\"; }}```

### 8.3 自定义三级缓存测试#### 8.3.1 测试类实现```j*apublic class CustomThreeLevelCacheTest { @Test public void testCustomThreeLevelCache() { System.out.println(\"\===== 自定义三级缓存循环依赖测试 =====\"); // 创建自定义Bean工厂 CustomBeanFactory beanFactory = new CustomBeanFactory(); // 注册Bean定义,声明循环依赖关系 beanFactory.registerBean(\"beanA\", BeanA.class, \"beanB\"); beanFactory.registerBean(\"beanB\", BeanB.class, \"beanA\"); System.out.println(\"\开始获取BeanA(触发循环依赖解决过程)...\"); // 获取BeanA,这将触发循环依赖的解决过程 BeanA beanA = beanFactory.getBean(\"beanA\"); // 验证循环依赖解决结果... } @Test public void testDetailedCacheProcess() { // 详细测试三级缓存的工作流程... }}```

#### 8.3.2 核心实现类**CustomSingletonBeanRegistry**:实现三级缓存核心逻辑

```j*apublic class CustomSingletonBeanRegistry { // 一级缓存:存储完全初始化好的单例Bean private final Map\u003cString, Object\u003e singletonObjects = new ConcurrentHashMap\u003c\u003e(256); // 二级缓存:存储早期曝光的Bean实例 private final Map\u003cString, Object\u003e earlySingletonObjects = new HashMap\u003c\u003e(16); // 三级缓存:存储Bean工厂对象 private final Map\u003cString, CustomObjectFactory\u003c?\u003e\u003e singletonFactories = new HashMap\u003c\u003e(16); // 获取单例Bean的核心方法 public Object getSingleton(String beanName) { // 1. 先从一级缓存获取 // 2. 如果不存在且Bean正在创建中,从二级缓存获取 // 3. 如果二级缓存也不存在,从三级缓存获取工厂对象 // 4. 通过工厂获取早期引用并升级到二级缓存 } // 其他关键方法:registerSingleton, addSingletonFactory等}```

**CustomBeanFactory**:实现Bean创建和管理

```j*apublic class CustomBeanFactory { private final CustomSingletonBeanRegistry singletonRegistry = new CustomSingletonBeanRegistry(); public \u003cT\u003e T getBean(String beanName) { // 1. 先尝试从缓存获取 // 2. 标记Bean为正在创建中 // 3. 创建Bean实例 // 4. 添加到三级缓存 // 5. 注入依赖 // 6. 初始化Bean // 7. 注册到一级缓存 }}```

### 8.4 对比分析结果#### 8.4.1 执行流程对比| 执行阶段 | Spring原生实现 | 自定义实现 || --- | --- | --- || 初始化阶段 | 使用Spring容器和注解 | 手动注册Bean定义 || Bean实例化 | 通过反射和BeanDefinition | 简化的反射创建 || 依赖注入 | 基于Autowired注解和类型匹配 | 基于预先声明的依赖关系 || 循环依赖处理 | 自动使用三级缓存 | 手动实现的三级缓存逻辑 || 执行效率 | 完整但较重 | 简化但高效(示例场景下) |

#### 8.4.2 输出结果对比**Spring原生实现输出:**

```plainServiceA构造函数被调用ServiceB构造函数被调用ServiceB的setServiceA方法被调用ServiceA的setServiceB方法被调用

===== Spring三级缓存循环依赖测试 =====ServiceA调用结果: ServiceA调用ServiceB: Hello from ServiceB验证循环依赖是否解决:- ServiceA的serviceB引用: Hello from ServiceB

对象引用验证:- ServiceA实例: com.example.cache.ServiceA@1a2b3c4d- ServiceB实例: com.example.cache.ServiceB@5e6f7g8h```

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【 手撕Java源码专栏 】深入理解Spring三级缓存:从源码到实践,彻底解决循环依赖

**自定义实现输出:**

```plainBeanA constructor calledBeanB constructor calledBeanB injected with BeanABeanA injected with BeanB

===== 自定义三级缓存循环依赖测试 =====BeanA的消息: Hello from BeanA, using injected BeanBBeanB的消息: Hello from BeanB, using injected BeanA

验证循环引用的一致性:- beanA.getBeanB() == beanB: true- beanB.getBeanA() == beanA: true```

【 手撕Java源码专栏 】深入理解Spring三级缓存:从源码到实践,彻底解决循环依赖

#### 8.4.3 核心差异分析1. **实现复杂度**: - Spring原生实现:非常复杂,有完善的异常处理、事件机制、生命周期回调等 - 自定义实现:简化版本,只保留了核心的三级缓存逻辑2. **扩展性**: - Spring原生实现:高度可扩展,支持各种BeanPostProcessor、FactoryBean等 - 自定义实现:基本无扩展性,仅用于演示三级缓存原理3. **AOP支持**: - Spring原生实现:完整支持AOP代理的创建和应用 - 自定义实现:简化版,未实现完整的AOP代理支持4. **循环依赖处理效果**: - 两种实现都能成功解决setter注入的循环依赖 - 都无法解决构造器注入的循环依赖

### 8.5 实践效果与结论通过这次手写实现和对比测试,我们得到以下重要结论:

1. **三级缓存的核心价值**:通过提前暴露Bean引用,成功打破了循环依赖的死锁2. **实现的灵活性**:Spring的设计允许在不同场景下正确处理各种复杂依赖关系3. **学习价值**:通过手写实现,更深入地理解了Spring框架的内部机制

尽管我们的自定义实现与Spring原生实现有很大差距,但核心的三级缓存思想是一致的,这也证明了Spring设计的精妙之处。

## 九、总结与最佳实践### 9.1 三级缓存核心总结Spring的三级缓存机制是一个精巧的设计,它通过以下方式解决了循环依赖问题:

1. **提前暴露引用**:在Bean完全初始化前就暴露其引用2. **缓存升级机制**:随着Bean初始化的推进,引用在不同级别缓存间移动3. **支持AOP代理**:通过ObjectFactory延迟创建代理对象

### 9.2 实际开发中的最佳实践1. **尽量避免循环依赖**:循环依赖通常表示设计存在问题,应该通过重构消除2. **优先使用构造器注入**:虽然不能解决循环依赖,但更符合面向对象设计原则3. **合理使用@Lazy注解**:可以解决某些构造器注入的循环依赖问题4. **考虑使用接口分离**:将Bean的功能拆分为多个接口,可能有助于消除循环依赖

### 9.3 深入学习的建议1. **阅读Spring源码**:特别是DefaultSingletonBeanRegistry类2. **调试Spring启动过程**:观察Bean的创建和缓存过程3. **尝试自己实现**:像本文一样,手写一个简化版的三级缓存4. **对比测试**:通过对比原生和自定义实现,更深入理解Spring的工作原理

通过本文的介绍和代码实现,相信你已经对Spring三级缓存有了深入的理解。这不仅有助于你在面试中应对相关问题,也能帮助你更好地理解Spring框架的工作原理。

如果你有任何疑问或建议,欢迎在评论区留言讨论!

---

以上就是【 手撕J*a源码专栏 】深入理解Spring三级缓存:从源码到实践,彻底解决循环依赖的详细内容,更多请关注其它相关文章!


# 两级  # 掇刀关键词优化排名前十  # 肇庆网站建设效果  # 韩都衣舍的营销推广模式  # 营销推广人员配置方案  # 供应产品网站制作和推广  # 汕尾谷歌seo报价  # 快手推广网站链接是什么样的  # 人大建设网站  # 手游推广营销方案书  # 排名好的锦州网站建设  # 是一个  # 彻底解决  # 移除  # 简化版  # 会在  # java  # 如何解决  # 递归  # 自定义  # fi  # red  # 为什么  # spring容器  # spring框架  # 区别  # win  # 注册表  # ai  #   # github  # git 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 6月14日《星空下的对话》 张朝阳陆川将畅聊人生、电影、心理学与AI  美图秀秀发布七款 AI 工具:修图一样修视频、打造电影级上镜脸  AI在教育中的角色:AI如何改变我们的学习方式  物联网“僵尸网络DDos攻击”增长惊人,威胁全球电信网络  黄仁勋:5年前,我们对AI抱有巨大期望  XREAL发布新款硬件XREAL Beam投屏盒子:可悬停AR空间屏  视觉中国宣布推出AI灵感绘图、画面扩展功能  人形机器人打开精密齿轮市场全新空间!受益上市公司梳理  盘古大模型3.0正式发布 AI开发正走向新“工业化开发模式”  基于信息论的校准技术,CML让多模态机器学习更可靠  “直击”AI新世界,智能机器人再次“火出圈”了  全新升级的广州麦当劳:面积最大餐厅正式引入智慧机器人  看懂AI,找到增长新势能 | 笔记侠AI峰会等你来  国内AI大模型“安卓时刻”到来!阿里云通义千问免费、开源、可商用  争鸣:OpenAI奥特曼、Hinton、杨立昆的AI观点到底有何不同?  【首发】首款“消化内镜手术机器人”进入临床尾声,ROBO医疗获数千万元A轮融资  成都大运会闭幕式引入人形机器人展示表演  江永:精准施训提升通信无人机应急救援能力  关于开展“与AI共创未来”——2025年全国青少年人工智能创新实践活动的通知  重磅! 捷通华声灵云AICC荣获第二届光合组织AI解决方案大赛二等奖  研究预测HPC支持的人工智能增长迅速  一文读懂自动驾驶的激光雷达与视觉融合感知  “长沙造”无人机,领先的不止植保  有 ARM 和 X86 两个版本,香橙派游戏掌机细节曝光  OpenAI首席执行官表态支持欧盟AI监管  发布最新版本的 PICO OS 5.7.0:支持VR头盔录屏并跨平台分享至微信  直击上影节 | 光线传媒董事长王长田谈新技术:未来VR放映效果可能媲美影院  聚焦WAIC|AI技术支撑大模型探索未来  学而思网校推出首个基于自研大模型的《人工智能第一课》  重塑未来生活的五项技术趋势  业内领先 四川大学华西第四医院甲状腺乳腺外科成功进入手术机器人时代  AI 作画工具 Midjourney 推出“pan”功能,可平移扩展图片外场景  阿里云AI绘画创作大模型通义万相发布 已开启定向邀测  特斯拉 Optimus 人形机器人入驻北美门店,帮助提升汽车销量  研究发现AI聊天机器人ChatGPT不会讲笑话,只会重复25个老梗  第 66 届格莱美奖规定,AI 作品将无法获得评奖资格  九号公司主导制定短途交通和送物机器人领域首个国际标准,标志着零的突破发布  从谷歌到亚马逊,科技巨头们的AI痴迷  印象笔记开放旗下“印象 AI”,可一键生成思维导图、写文章等  揭晓2025年玻尔兹曼奖:Hopfield网络创始人荣获奖项  Nature封面:量子计算机离实际应用还有两年  湖北科技职业学院举行工业机器人及智能制造技术专精特新产业学院建设启动仪式  让AI助手带您轻松愉快地享受写作之旅  OpenAI宣布在伦敦设立海外分部,要招揽“世界级人才”  放弃自动驾驶,也是一种和解  走进首家“元宇宙”未来工厂,卡奥斯探知工业之旅出发!  Meta将VR头显最低年龄限制从13岁降至10岁  海柔创新携手SAP,以机器人技术助力全球客户升级数智化竞争力  首家承认ChatGPT影响其收入的公司Chegg选择拥抱AI ,裁减4%员工  稿见AI助手:提升写作效率与质量的必备工具 

 2025-12-03

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.