spring循环依赖

一、什么是循环依赖

循环依赖是指一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用 , 举个例子 : A 依赖B , B依赖C , C依赖A , 这样就形成了循环依赖

Spring解决循环依赖问题, 靠的是三级缓存机制 , Spring中的三级缓存

  • 第一级缓存:singletonObjects,用于保存实例化、注入、初始化完成的 bean 实例
  • 第二级缓存:earlySingletonObjects,用于保存实例化完成的 bean 实例
  • 第三级缓存:singletonFactories,用于保存 bean 创建工厂,以便后面有机会创建代理对像

三级缓存的执行逻辑

  • 先从“第一级缓存”找对象,有就返回,没有就找“二级缓存”
  • 找“二级缓存”,有就返回,没有就找“三级缓存”
  • 找“三级缓存”,找到了,就获取对象,放到“二级缓存”,从“三级缓存”移除

 二、各级缓存的作用

1.一级缓存的作用

限制某一个Bean,在BeanFactory中只存一份,实现单例池;

1.当第一次getBean时,在单例池去找,当然是找不到的;

2.然后就会创建一个对象,然后就把该对方放入一级缓存;

3.下次再调用getBean时,可以找到这个对象。

 2.一级缓存存在的问题

一级缓存不能解决循环依赖问题

1.当get一个A的Bean时,单例池中没有A对象;

2.然后就会创建一个A的实例,再对A进行依赖注入;

3.然后就需要set一个B对象进去,调用getBean获取B对象

4.单例池里没有B对象,那么就会实例一个B对象,

5.然后B又需要set一个A,如此就进入了死循环。

 

这时候我们就需要引入一个新的环境:二级缓存 

3.二级缓存的作用

二级缓存(spring中它叫三级缓存),singletonFactories。作用:解决循环依赖

1.当我们需要get A的Bean时,在A被实例后,就把半成品的A存到二级缓存中。

2.下一步就去二级缓存中获取半成品的B,这时候二级缓存中还没有B。

3.下一步就走get B的Bean流程,首先去一级缓存找,一级缓存没有就创建B的实例。

4.然后把B的半成品放入二级缓存中。

5.然后set A的时候,能在二级缓存中找到半成品的A,然后B就可以进行依赖注入并初始化。

6.最后成品的B对象会进入一级缓存,二级缓存中的B只是临时引用,这时候被清理掉,然后再去完成A的依赖注入。

7.A完成初始化,进入一级缓存后,二级缓存的A就会被清理掉

4.二级缓存存在的问题

当我们已经完成了A的初始化之后,我们需要给A增强时,需要给A,B创建一个代理对象,

1.重复上面的流程到B实例化后,创建一个B的代理对象,并把代理B存入到一级缓存

2.然后A完成set b,完成A的初始化,然后创建A的代理,最后把A的代理对象存入一级缓存中。

然鹅,B在依赖注入A的时候有漏洞,B注入的是一个半成品的A,将来使用代理A调用到B相关的功能的时候,它用到了A,此时的A是原始的A,并不是增强的A

这就是二级缓存遇到代理对象时遭遇的问题。

5.三级缓存的作用

遇事不决,再加一层,对于上面说到的代理对象的问题,

我们需要用到三级缓存earlySinletonObjects(spring中它叫二级缓存)

 三级缓存配合一个工厂使用

当二级缓存中找不到代理对象时,三级缓存中的工厂会生成一个代理对象,否则返回一个原始对象

1.在A和B实例化后就会在二级缓存中放入一个工厂对象

2.当A要实例化后需要注入B时,B也要注入A,此时B就在三级缓存中找到了A的工厂对象

3.然后判断是否发生了代理对象的循环依赖,如果发生了工厂就返回一个代理对象,没发生就返回一个普通对象,同时在三级缓存中存入一个代理对象

4.A初始化之后会检查代理对象有没有创建,此时回去三级缓存中找,找到了就直接使用缓存中的代理对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值