【卷Spring系列】请说一下循环依赖

什么是循环依赖

简单来说就是,A依赖B,B依赖A

image-20211206163256032
img

详细来说,循环依赖是这样产生的:

  1. 先创建A对象,实例化A对象,此时A对象中b属性为空,填充属性b
  2. 从容器中查找B对象,如果找到了,直接赋值就不存在循环依赖的问题,找不到就需要直接创建B对象
  3. 实例化B对象,此时B对象中的a属性为空,填充属性a
  4. 从容器中查找A对象,找不到,直接创建
image-20211206163923563

此时,图中是一个闭环,如果想解决问题,那么就必须保证不会出现第二次创建A对象的这个步骤,也就是说从容器中获取A的时候,必须要能够获取的到。

在Spring中,对象的创建可以分为实例化和初始化,实例化好但未完成初始化的对象是可以直接给其他对象引用的,所以此时可以做一件事,把完成实例化但未完成初始化的对象暴露出去,让其他对象能够进行引用,就完成了这个闭环的解环操作。

如何解决循环依赖

此时,如果仔细琢磨的话,会发现A对象是存在的,只不过此时的A对象不是一个完整的状态,只完成了实例化但是未完成初始化,如果在程序调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先把非完整状态的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整对象的引用,所以解决问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键,

当所有的对象都完成实例化和初始化操作之后,还要把完整对象放到容器中,此时在容器中存在对象的几个状态,完成实例化=但未完成初始化,完整状态,因为都在容器中,所以要使用不同的map结构来进行存储,此时就有了一级缓存和二级缓存,如果一级缓存中有了,那么二级缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3这样的方式来查找的。一级缓存中放的是完整对象,二级缓存中放的是非完整对象

Spring运用三级缓存解决循环依赖

image-20211206164835429

Spring中运用了三级缓存来解决循环依赖的问题,也就是三个Map:

第一级缓存SingletonObjects,存放已经经历了完整生命周期的Bean对象

第二级缓存earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完)

第三级缓存singletonFactories,存放可以生成Bean的工厂

A、B两对象在三级缓存中的迁移说明
  1. A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
  2. B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存,并删除三级缓存里面的A
  3. B顺利初始化完毕,并将自己放到一级缓存(此时B里面的A依然是创建中的状态)然后回来接着创建A,此时B已经创建结束了,直接从一级缓存里面拿到B,然后完成创建,并将A自己放入到一级缓存里面
只用二级缓存行不行

只有二级缓存的时候可以解决循环依赖的问题,添加aop的实现之后,报错

三级缓存是为了解决在aop代理过程中产生的循环依赖问题,如果没有aop的话,二级缓存足以解决循环依赖的问题

脑图

Spring内部通过三级缓存来解决循环依赖的问题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦客子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值