详细解释一下Spring是如何解决循环依赖问题的

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

我们都知道,如果在代码中,将两个或多个Bean互相之间持有对方的引用就会发生循环依赖。循环的依赖将会导致注入死循环,这是Spring发生循环依赖的原因

循环依赖有三种形态

1.互相依赖:
A依赖B , B依赖A , 他们之间形成了循环依赖
image

2.间接依赖:
A依赖B ,B依赖C , C又依赖A,形成了循环依赖
image

3.自我依赖:
A依赖A形成了循环依赖
image

Spring中的三级缓存

Spring中设计了三级缓存来解决循环依赖问题,当我们去调用getBean()方法的时候:
1> Spring会先从一级缓存中去找到目标Bean,如果发现一级缓存中没有便会去二级缓存中去找
2> 如果一、二级缓存中都没有找到,意味着该目标Bean还没有实例化**(早期Bean)。于是,Spring容器会实例化目标Bean**,然后将目标Bean放入到二级缓存中,同时,加上标记是否存在循环依赖。如果不存在循环依赖便会将目标Bean存入到二级缓存
3> 否则,便会标记该Bean存在循环依赖,然后将等待下一次轮询赋值,也就是解析**@Autowired注解**。等@Autowird**(成熟Bean)**,会将目标Bean存入到一级缓存

第三级缓存的作用是用来存储代理Bean的,当调用getBean()方法之后,发现目标Bean需要通过代理工程来创建,此时会将创建好的实例保存到三级缓存,最终也会赋值好的Bean同步到一级缓存中

早期Bean:刚初始化的Bean

成熟Bean:完成注入的Bean

在Spring三级缓存的设计下,我画了一张图来描述一下其工作原理:
image

Spring本身只能解决单实例存在的循环依赖问题,存在以下四种情况需要人为干预:
1> 多实例的Setter注入导致的循环依赖,需要把Bean改成单例
2> 构造器注入导致的循环依赖,可以通过@Lazy注解
3> DependsOn导致的循环依赖,找到注解循环依赖的地方,迫使它不循环依赖
4> 单例的代理对象Setter注入导致的循环依赖
① 可以使用Lazy注解
② 或者使用@DependsOn注解指定加载先后关系

在实际开发中,出现循环依赖的根本原因还是在代码设计的时候,因为模块的耦合度较高依赖关系复杂导致的,我们应该尽可能地从系统设计角度去考虑模块之间的依赖关系,避免循环依赖地问题。

三级缓存的核心思想:就是把Bean的实例化和Bean里面的依赖注入进行分离

总结:

① 采用一级缓存存储成熟Bean实例,采用二级缓存来存储早期Bean实例
② 通过早期Bean实例作为突破口,解决循环依赖问题。
③ 至于第三级缓存,主要是解决代理对象的循环依赖问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值