Spring是如何解决循环依赖问题的?

Spring通过三级缓存解决循环依赖问题,包括singletonObjects(一级缓存,存放完全创建好的单例bean)、earlySingletonObjects(二级缓存,存放尚未完全创建的bean)和singletonFactories(三级缓存,存放bean的生成工厂)。在循环依赖时,Spring使用三级缓存中的Lambda表达式判断是否需要进行AOP并生成代理对象,避免提前进行AOP操作与bean生命周期的冲突。某些特定场景如构造器注入、原型bean循环依赖、@DependsOn注解和@Async注解导致的循环依赖,Spring无法解决。
摘要由CSDN通过智能技术生成

什么是Spring中的循环依赖问题?

注意这个问题与JVM中垃圾回收时的循环依赖问题进行区分。

JVM中垃圾回收时的循环依赖问题可以参考这篇博客中的垃圾回收部分。

Spring中的循环依赖问题是指IOC的加载过程当中bean创建的时候发生的,如下图所示,比如说当我们IOC加载创建BeanA的时候首先会去实例化A,然后进行属性注入解析@Autowired注解,发现依赖一个BeanB,这个时候会去IOC容器中帮我们去找BeanB,如果没有找到那么同样会先实例化B,然后进行属性注入解析@Autowired注解又发现依赖BeanA,这个时候又去IOC容器当中去拿BeanA,然后又没有拿到,又会去帮我们创建BeanA,就形成了一个闭环死循环。

答案:Spring则通过三级缓存来解决循环依赖问题。

循环典型的场景有以下三种:1.自我依赖。2.相互依赖。3.多个bean之间的依赖。比如A依赖B,B依赖C,…,而N又依赖A。

请添加图片描述

正常我们在创建Bean的时候完全可以通过先创建A和B两个对象的方法解决循环依赖,但是Spirng在创建非懒加载单例bean的时候出现循环依赖的问题是因为Spring的对象创建过程分为创建对象——实例化——属性填充三个过程。

请添加图片描述



什么是Spring中的三级缓存?

为了解决循环依赖问题,Spring 引入了三级缓存。那么,什么是 Spring 的三级缓存呢?首先,让我们看一下它们在DefaultSingletonBeanRegistry类中的定义,其实它们本质上就是一个Map。

请添加图片描述

—级缓存

一级缓存被命名为singletonObjects,也被称作单例池,它存储的是经历了完整的创建过程的单例 bean对象。一级缓存是一个ConcurrentHashMap,它的 key是String 类型,保存的是beanName; value 是Object 类型,保存的创建好的单例bean对象。

单例池并非专门用于解决Spring 的循环依赖问题,即便不考虑循环依赖,经历了Spring容器完整创建过程的单例 bean对象也会被放进该单例池。只不过在Spring解决循环依赖问题的三级缓存中被称为一级缓存。

单例池的主要作用是用来保证这些完全创建好的 bean是单例的。


二级缓存

二级缓存被命名为earlySingletonObjects,它存储的是尚未完全创建好的单例 bean对象。二级缓存的存储结构和一级缓存完全一样,只不过它们存储的对象有所不同,一个是已经创建好的完整的 bean对象;另外一个则是尚未创建好的单例 bean对象或者叫半成品对象。
在创建单例bean时,如果发现该bean存在循环依赖,则会提前把这个尚未完全创建好的半成品对象放入到二级缓存中。如果该bean需要进行AOP,则该半成品对象就是它的代理对象,否则就是它实例化之后但是尚未属性填充的原始对象。

二级缓存的主要作用是用来保证这些尚未完全创建好的半成品对象是单例的。


三级缓存
三级缓存被命名为singletonFactories,它存储的是尚未完全创建好的单例 bean对象的生成工厂。三级缓存是一个HashMap,它的key 是String类型,保存的是beanName; value 是ObjectFactory类型,保存的是生成尚未创建好的单例 bean的对象工厂。
可能有些小伙伴对ObjectFactory有点陌生,它其实是Spring 提供的一个函数式接口,既然是函数式接口,我们就可以使用Lambda 表达式进行实现,并且可以在任何我们需要结果的时候才真正去执行Lambda表达式。

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值