Spring的循环依赖和三级缓存

转载

https://blog.csdn.net/bntX2jSQfEHy7/article/details/111658814

Spring有著名的三级缓存

  • singletonObjects:【一级缓存】 存储的是所有创建好了的单例Bean
  • earlySingletonObjects:【二级缓存】完成实例化,但是还未进行属性注入及初始化的对象
  • singletonFactories:【三级缓存】提前暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象

一般而言,一个Spring对象创建分为三个部分

  • new一个对象
  • 为上面new出来的对象填充属性
  • 初始化,执行aware接口中的方法和相关初始化方法,并完成AOP代理

普通的循环依赖如图
在这里插入图片描述
从上面可以看到,三级缓存中存储的对象工厂其实没有任何实际作用。其中,我们是先创建了A对象,然后根据这个对象创建的工厂。完全可以支用二级缓存进行解决。

带AOP循环依赖图
在这里插入图片描述
和上面的区别是,A对象的的工厂返回的是A对象的代理。注意,并不是真正生成A的对象的代理,而是只会将三级缓存中加入这个工厂。
只有真正发生循环依赖的时候,才去利用这个工厂提前生成代理对象,

一个完成的spring bean的生命周期为
在这里插入图片描述
如果没有循环依赖,postProcessAfterInitialization后对bean添加AOP代理。现在有循环代理了,没有办法,只能提起你生成。

如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

### Spring 框架中的三级缓存机制 Spring 容器通过其内部实现的三级缓存来解决单例 Bean 的循环依赖问题。以下是关于这一主题的具体说明: #### 单例 Bean 循环依赖概述 在 Spring 中,当两个或多个 Bean 形成相互依赖的关系时,就会发生循环依赖。例如,Bean A 依赖于 Bean B,而 Bean B 又反过来依赖于 Bean A。这种情况下,默认构造函数注入可能会导致实例化失败。 为了处理这种情况,Spring 提供了一种基于 **三级缓存** 的解决方案[^1]。 #### 三级缓存的工作原理 Spring 使用三个不同的缓存结构来存储正在创建已经完成初始化的 Bean 实例。这些缓存分别是: 1. **`singletonObjects`**: 存储完全初始化后的单例对象。 2. **`earlySingletonObjects`**: 存储尚未完成初始化的对象(即早期暴露的对象)。 3. **`singletonFactories`**: 存储用于延迟加载的工厂方法。 具体流程如下: - 当容器尝试获取某个 Bean 时,它会先检查 `singletonObjects` 缓存是否存在该 Bean。如果存在,则直接返回。 - 如果不存在,继续检查 `earlySingletonObjects` `singletonFactories` 是否有对应的占位符或提前曝光的 Bean 实例。 - 在实际创建过程中,Spring 首先将当前未完成的 Bean 放入 `singletonFactories` 或者 `earlySingletonObjects` 中作为临时状态,以便其他 Bean 能够访问到这个部分构建好的实例。 一旦所有的依赖都已解析完毕并完成了必要的后置处理器调用之后,最终完整的 Bean 就会被移至 `singletonObjects` 并清理掉中间阶段使用的缓存条目[^2]。 #### 示例代码展示 下面是一个简单的例子演示如何配置以及可能触发上述机制的情况: ```java @Component public class ServiceA { private final ServiceB serviceB; @Autowired public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } } @Component public class ServiceB { private final ServiceA serviceA; @Autowired public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } } ``` 在这个场景下,如果没有特别设置允许此类情况(Such as setting primary or qualifier annotations),则默认情况下,Spring能够自动利用它的三重缓冲策略去妥善管理这两个互相引用的服务组件. #### 局限性注意事项 尽管如此强大的功能可以帮助我们简化很多复杂关系的设计考量,但也并非适用于所有场合: - 原型(Prototype)作用域下的 bean 不支持此方式解决循环依赖. - 对某些自定义生命周期或者特殊需求的应用程序来说,过度依赖框架自带的行为可能导致不可预测的结果.[^3] ### 结论 综上所述,Spring Framework确实具备一套完善的体系用来应对常见的开发难题之一——循环依赖问题;借助精心设计过的多级内存映射技术实现了优雅高效的资源调配方案.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值