彻底理解Spirng中的依赖循环是如何解决的!

什么是循环依赖?

BeanA 类依赖了 BeanB 类,同时 BeanB 类又依赖了 BeanA 类。这种依赖关系形成了一个闭环,我们把这种依赖关系就称之为循环依赖。
在这里插入图片描述

解决循环依赖的步骤:

简单来讲就是因为Spring对Bean的管理大体分为两个阶段吧:第一个阶段:在Spring容器加载的时候,实例化Bean,只要其中任意一个Bean实例化之后,马上进行 “曝光”【属性赋值此时还没赋值,类似于无参构造】第二个阶段:Bean“曝光”之后,就可以再进行属性的赋值(DI)。当然里面具体的实现其实就是依靠着spring的三级缓存机制嘛。

具体步骤

假设A依赖B,B依赖A

step1: A先去一级缓存找,因为没找到,所以要创建一个空壳子、也就是没有DI的对象(类似空构造器的对象)。然后这个时候其实是会把这个半成品放入三级缓存。【曝光】

step2: 然后就准备开始DI了,所以这个时候就要去注入属性B、然后因为从一二三级缓存没找到B,所以就开始去创建B了。然后B也是一样、因为一级缓存没找到,所以就是也创建一个空壳子对象,然后放入三级缓存里。

step3: 这个时候,就要进行DI操作了,然后先去一级缓存找,没找到,然后去二级,没找到。这个时候三级找到了,然后因为三级缓存就是一个bean工厂,然后内部有一个lambda表达式【是为了判断是否进行AOP的一个必要步骤】,之后lambda表达式就会执行了,将三级缓存的A对象【如果是aop就是代理对象】放入二级缓存里。放入之后,把三级的缓存A对象清理掉,注入到B对象里。

step4: 所以这个时候B对象就是个完整对象了,然后B对象就是会放入一级缓存,并且把三级缓存的B清理掉。

step5: 这个时候我们就回到A要DI的步骤,这个时候因为B对象以及在一级缓存了,所以我们可以直接注入了,然后二级缓存的A对象清理掉,然后循环依赖解决了。

注意点:

1.为什么要有三级缓存?
这个主要是是为了解决出现循环依赖时的AOP问题的,不然有二级缓存就够了。因为放入单例池的是代理对象(如果是AOP操作)如果初始化后进行AOP,而我们这个是初始化操作…

2.lambda作用是啥?
判断是否进行AOP操作

3.AOP不都是初始化后操作么,那么这样的话,初始化后的AOP操作不是重复了吗?
初始化后的AOP操作会执行一个方法,那个方法里面有个if,它来判断我们之前是否进行过AOP操作,如果进行了,那么我们就不会再进行AOP操作了。如果没进行,那么就进行AOP操作。

4.所以一级缓存叫做singletonObjects【用于存放完全初始化的单例bean】,二级缓存交earlysingletonObiects【早期的单例对象“因为没有D!,所以是不完整的】,三级缓存叫做singletonFactories【bean工厂,用于解决循环依赖】

追问:一定要三级缓存吗?不能只有二级缓存吗?

不行,主要是为了代理对象 。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。

因为三级缓存中放的是生成具体对象的匿名内部类【lambda表达式】,获取Object的时候,它可以生成代理对象,也可以返回普通对象。使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,Bean初始 化过程中,通过 BeanPostProcessor 去生成代理对象之后,覆盖掉二级缓存中的普通 Bean对象,那么可能就导致取到的Bean对象不一致了。

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring解决循环依赖的方法是使用三级缓存。当Spring容器初始化Bean时,会将正在创建的Bean对象放入第一级缓存。如果发现有循环依赖的情况,Spring会将正在创建的Bean对象提前暴露给其他Bean,但此时Bean对象还未完成初始化。然后,Spring会将正在创建的Bean对象放入第二级缓存,并继续创建其他Bean。当其他Bean需要依赖该Bean时,Spring会从第二级缓存获取正在创建的Bean对象,以满足依赖关系。最后,当Bean对象完成初始化后,Spring会将其放入第三级缓存,并完成整个Bean的创建过程。通过使用三级缓存,Spring能够解决循环依赖的问题,确保Bean对象的正确创建和依赖注入。\[2\]\[3\] #### 引用[.reference_title] - *1* [Spring如何解决循环依赖](https://blog.csdn.net/m0_46420244/article/details/126215891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Spring 源码复习 01 IOC](https://blog.csdn.net/kuaipao19950507/article/details/100978308)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Spring 如何解决循环依赖的问题](https://blog.csdn.net/qq_36381855/article/details/79752689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值