Spring如何解决循环依赖

Spring通过三级缓存机制(singletonObjects,earlySingletonObjects,singletonFactories)处理循环依赖,提前暴露Bean实例并拆分实例化和初始化过程,确保代理对象在适当时候创建,避免了直接创建可能导致的循环。
摘要由CSDN通过智能技术生成

Spring 使用了三级缓存来解决循环依赖问题。当两个或多个 Bean 之间存在循环依赖时,Spring 会使用以下步骤来解决:

  1. 提前暴露中间对象:Spring 在创建 Bean 实例的过程中,会先创建一个对象实例并放入一级缓存(singletonObjects)。这个过程中,如果遇到循环依赖,则会提前暴露正在创建的 Bean 实例,而不是等到创建完成后再放入缓存中。

  2. 使用三级缓存:如果 Bean A 依赖于 Bean B,同时 Bean B 也依赖于 Bean A,则在创建 Bean A 的过程中会触发创建 Bean B,而在创建 Bean B 的过程中又会触发创建 Bean A,导致循环依赖。为了解决这个问题,Spring 引入了三级缓存。

    • 一级缓存(singletonObjects):存放已经创建的 Bean 实例。这是 Spring 中最常见的缓存级别,这是最终存放完全初始化的 Bean 实例的缓存,也就是说,所有 Bean 初始化完毕后,都会放入该缓存中。以便后续被其他 Bean 引用或注入。这个缓存通常用于存放单例 Bean 的实例。
    • 二级缓存(earlySingletonObjects):存放正在创建中的没有被初始化的 Bean 实例。这是存放早期(early)初始化的 Bean 实例的缓存时,Bean 的实例化和初始化被拆分成了两个阶段:第一阶段是实例化 Bean,但不进行属性注入和初始化;第二阶段是在实例化后的 Bean 被首次访问时进行属性注入和初始化。这样,就可以避免循环依赖导致的 Bean 初始化失败。这样的 Bean 实例可以被提前暴露给其他 Bean 进行依赖注入,但是尚未完成完全的初始化。当创建一个 Bean 实例时,Spring 会先创建一个对象实例并放入二级缓存中,以防止循环依赖时的死循环。这个缓存通常用于解决循环依赖问题。
    • 三级缓存(singletonFactories):存放用于创建 Bean 实例的工厂对象。这个缓存用于存放创建 Bean 实例的工厂对象。当一个 Bean 需要被代理时,Spring 会先创建一个代理工厂对象并放入三级缓存中,而不是直接创建实例。这个缓存通常用于创建代理对象,并解决循环依赖时创建代理对象的问题。
  3. 使用代理对象:在创建 Bean  A实例时,如果发现当前 Bean 需要被代理切和Bean B循环依赖,1)Spring 会先创建一个代理工厂对象,并放入三级缓存中。2)实例化A,并将其放在二级缓存中,3)创建 Bean  B的这个时候bean B可以引用到没有被初始化的A(A实例化后就可以被引用了所以B引用的到A),4)将B放到一级缓存中,A直到所有依赖 Bean 创建完成。这个时候A可以被初始化了,那么这个时候,Spring 会调用代理工厂对象的 getObject 方法来获取A的代理对象(代理对象的初始化会先初始化被代理对象,因为这个时候A的依赖都解决完了所以可以被初始化了,那么这里其实就是用了延迟初始化,也就是将bean的实例化和初始化时机分开了,等准备好再初始化来避免循环依赖的问题),这个代理对象工厂存放在三级缓存中,待循环依赖解决后,再通过代理对象工厂来创建代理对象,从而完成 Bean 的初始化,并将代理对象放入一级缓存中。

  4. 三级缓存一般是针对代理对象工厂的缓存普通的工厂对象不会存放,用于解决循环依赖中代理对象的创建问题。当Bean需要被代理时,Spring会将其代理对象工厂缓存到三级缓存中,以便后续使用。(注意存放的是代理对象的工厂对象并不是代理对象本身)

  5. 延迟初始化Bean 的实例化和初始化被拆分成了两个阶段:第一阶段是实例化 Bean,但不进行属性注入和初始化;第二阶段是在实例化后的 Bean 被首次访问时进行属性注入和初始化。代理对象的工厂对象放入三级缓存中,(意思就是先不创建代理对象,等被代理初始化好后再来创建代理对象)可以延迟被代理对象的初始化过程。代理对象可以在之后的依赖注入阶段再去触发被代理对象的初始化,从而避免了在处理循环依赖时对被代理对象的直接初始化。

通过这种方式,Spring 可以确保循环依赖时创建的 Bean 是代理对象,从而在解决循环依赖的同时保持了 AOP 功能的完整性。

常见的疑问:

1  当一个Bean需要被代理时,而该Bean又依赖于另一个Bean,如果直接创建代理对象可能导致循环依赖问题,这个是为什么

直接创建代理对象可能导致循环依赖问题的原因主要是因为代理对象的创建通常会触发被代理对象的初始化,而被代理对象的初始化又依赖于另一个Bean。这样就形成了一个循环依赖的局面。

第三级缓存用于缓存代理对象的工厂对象。这个工厂对象是用来创建真正的代理对象的,而不是代理对象本身。

存放代理对象的工厂对象的目的是为了在需要使用代理对象的时候能够快速获取已经创建好的代理对象,而不需要重新创建。这样可以避免重复创建代理对象,提高系统的性能和效率。

总的来说,三级缓存的作用是在处理循环依赖时提供一种机制,确保代理对象的创建和使用能够顺利进行,避免循环依赖导致的问题。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值