学无先后,达者为师

网站首页 编程语言 正文

spring如何解决循环依赖

作者:l1050188952 更新时间: 2022-09-25 编程语言

在解决循环依赖问题之前我们先了解一下什么是循环依赖

        依赖就是Bean之间的引用关系,当引用互相持有时形成闭环,这就是循环依赖。分为三种情况:1.自己依赖自己的直接依赖 

2.两个bean对象之间的直接依赖

 

3.多个bean之间的简介依赖

 

 依赖注入的时机在上一篇Bean的生命周期中我们有讲到,实例化-->属性赋值-->初始化

对于一个单例Bean来说整个容器只有一个,在初始化时解决循环依赖问题就非常方便,Spring是使用了三级缓存的形式解决的。

三级缓存:

singletonObjects:单例对象的cache(存储器,快速,循环使用)单例池容器,缓存创建好的单例Bean的地方

earlySingletonObjects :提前曝光的单例对象的Cache(存储器,快速,循环使用),早期曝光的单例对象,用于保存实例化后的Bean,此时的Bean还是不完整的

singletonFactories : 单例对象工厂的cache(存储器,三级缓存),Bean的映射创建原始工厂,用于保存Bean的创建工厂

在创建Bean时先在一级缓存中获取,代码如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference//是否允许拿对象) {
//在一级缓存获取
  Object singletonObject = this.singletonObjects.get(beanName);
//没获取到
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)//判断当前Bean是否正在创建) {
   synchronized (this.singletonObjects) {
//二级缓存获取
    singletonObject = this.earlySingletonObjects.get(beanName);
//二级缓存没有
    if (singletonObject == null && allowEarlyReference) {
//三级缓存获取
     ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
     if (singletonFactory != null) {
//在三级缓存获取
      singletonObject = singletonFactory.getObject();
      this.earlySingletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
     }
    }
   }
  }
//返回以及或者二级或者三级缓存的singletonObject

  return singletonObject;
 }

从上面的代码可以看出,Spring解决循环依赖问题中,singletonFactories 三级缓存时设计的关键,在Bean第一次创建时发现以来的Bean没有,就会用构造方法先将自己曝光在三级缓存中,等待依赖的Bean被创建存入一级缓存时,在进行创建,虽然在三级缓存时不是一个完整的Bean,但是已经可以被识别了。

下图是TestService与TestService2的依赖注入图示 



 

TestService在第一次创建时,发现需要依赖的TestService2不存在,就先将自己曝光在三级缓存,在TestService2创建时,一二级内存都没有,曝光自己在三级缓存,在依赖属性有需要的TestService实例,在三级缓存发现,依赖属性注入成功,将自己存到一级缓存同时清楚二三级缓存,这时候TestService在一级缓存发现TestService2的依赖Bean,依赖属性注入成功,将自己存到一级缓存同时清楚二三级缓存

Spring不是所有的循环依赖都能解决,以下情况:

单例的setter注入 可以解决
单例的代理对象setter注入 不一定能解决
多例的setter注入 不能解决
构造器注入(构造方法先将自己曝光在三级缓存) 不能解决
DependsOn循环依赖 不能解决

Spring在三级缓存添加ObjectFactory对象,目的是为了更好对实例对象进行增强,直接用实例对象是行不通的。

二级缓存的作用在上面的图中没有体现出来,二级缓存的作用是在有间接循环依赖时(比如三个Bean之间相互依赖)存在两次从三级缓存获取不完整的同一个Bean,因为不完整所以可能会不一样。这时候就是二级缓存发挥作用的,在第一次三级缓存取得后就会在其二级缓存保留,下次再获取时直接在二级缓存,保证了一致性。

原文链接:https://blog.csdn.net/l1050188952/article/details/126208238

相关推荐

栏目分类
最近更新