spring解决bean的循环依赖问题

dalang · · 118 次点击 · · 开始浏览    
Spring 框架通过 **三级缓存机制** 解决单例 Bean 的循环依赖问题,同时确保代理对象(如 AOP 增强对象)的正确生成。以下是三级缓存的区别、作用及设计逻辑的详细分析: --- ### **一、三级缓存的定义与作用** | **缓存名称** | **存储内容** | **生命周期阶段** | **核心作用** | |---------------------------|-----------------------------------------------------------------------------|-------------------------------------|-----------------------------------------------------------------------------| | **一级缓存** `singletonObjects` | 完全初始化后的单例 Bean(包括代理对象) | Bean 完成实例化、属性注入、初始化后 | 提供最终可用的 Bean,避免重复创建 | | **二级缓存** `earlySingletonObjects` | 提前暴露的 Bean(可能是原始对象或代理对象),已实例化但未完成属性注入和初始化 | Bean 实例化后,但未完成初始化前 | 解决循环依赖,临时保存半成品 Bean,供其他 Bean 注入 | | **三级缓存** `singletonFactories` | 生成 Bean 的工厂(`ObjectFactory`),用于按需创建 Bean 的早期引用 | Bean 实例化后,但未开始属性注入前 | 延迟生成代理对象,确保循环依赖中注入的始终是增强后的 Bean | --- ### **二、三级缓存的协作流程** #### **1. 无循环依赖的场景** • **步骤**: 1. Bean 实例化后,生成原始对象,并注册 `ObjectFactory` 到 **三级缓存**。 2. 完成属性注入和初始化后,将 Bean 存入 **一级缓存**,并清理二、三级缓存。 • **特点**: 三级缓存仅在实例化阶段短暂存在,最终 Bean 直接进入一级缓存。 #### **2. 存在循环依赖的场景** 以 **Bean A 依赖 Bean B,Bean B 依赖 Bean A** 为例: 1. **创建 Bean A**: • 实例化 A(原始对象),注册 `ObjectFactory` 到 **三级缓存**。 • 开始注入属性时发现依赖 B,触发 B 的创建。 2. **创建 Bean B**: • 实例化 B(原始对象),注册 `ObjectFactory` 到 **三级缓存**。 • 开始注入属性时发现依赖 A,从 **三级缓存** 获取 A 的 `ObjectFactory`,生成 A 的早期引用(可能是代理对象),存入 **二级缓存**。 3. **完成 Bean B**: • B 注入 A 的早期引用后,完成初始化并存入 **一级缓存**。 4. **完成 Bean A**: • A 注入已初始化的 B,完成初始化并存入 **一级缓存**,清理二、三级缓存。 --- ### **三、关键设计逻辑** #### **1. 为什么需要三级缓存?** • **解决代理对象的唯一性**: 若直接使用二级缓存存储代理对象,当多个 Bean 依赖同一目标 Bean 时,可能导致代理对象重复生成。三级缓存的 `ObjectFactory` 通过延迟生成代理对象,确保全局唯一。 • **避免冗余判断**: 三级缓存通过工厂模式解耦代理生成逻辑,无需在每次获取 Bean 时检查是否需要代理。 #### **2. 与 AOP 代理的协作** • **代理对象的生成时机**: 在 `ObjectFactory` 的 `getObject()` 方法中,通过 `SmartInstantiationAwareBeanPostProcessor`(如 `AbstractAutoProxyCreator`)动态生成代理对象。 • **示例代码**: ```java // AbstractAutowireCapableBeanFactory#getEarlyBeanReference protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { // 生成代理对象(如需要) return ((SmartInstantiationAwareBeanPostProcessor) bp).getEarlyBeanReference(bean, beanName); } } return bean; // 无代理则返回原始对象 } ``` --- ### **四、示例:循环依赖 + AOP 代理** #### **场景** • Bean A 和 Bean B 相互依赖,且 Bean A 被 `@Transactional` 标记(需生成代理)。 #### **流程** 1. **创建 A**: • 实例化 A(原始对象),注册 `ObjectFactory` 到三级缓存。 • 注入 B 时触发 B 的创建。 2. **创建 B**: • 实例化 B(原始对象),注册 `ObjectFactory` 到三级缓存。 • 注入 A 时,从三级缓存获取 A 的 `ObjectFactory`,生成代理对象 ProxyA,存入二级缓存。 3. **完成 B**: • B 注入 ProxyA 后完成初始化,存入一级缓存。 4. **完成 A**: • A 注入 B 后,检查二级缓存发现已有 ProxyA,直接使用,最终存入一级缓存。 --- ### **五、总结** | **维度** | **一级缓存** | **二级缓存** | **三级缓存** | |------------------|---------------------------------|--------------------------------------|------------------------------------------| | **存储内容** | 完全初始化的 Bean | 提前暴露的半成品 Bean(可能为代理) | 生成 Bean 的工厂(用于按需创建代理) | | **存在意义** | 提供最终可用的 Bean | 临时解决循环依赖的引用问题 | 延迟生成代理,确保单例和增强逻辑正确性 | | **生命周期** | Bean 完全初始化后 | Bean 实例化后,初始化前 | Bean 实例化后,属性注入前 | **设计核心**: 通过三级缓存的协作,Spring 在保证单例的前提下,既解决了循环依赖问题,又确保 AOP 代理对象的正确性和唯一性。
118 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传