当前位置: 移动技术网 > IT编程>开发语言>Java > spring解决循环依赖

spring解决循环依赖

2020年09月30日  | 移动技术网IT编程  | 我要评论
概述循环依赖就是依赖关系形成环,比如最简单的循环依赖:a对象依赖b,b对象依赖a属性注入与循环依赖 如果是构造器注入,如果循环依赖对象没法构建,因为还未实例化 如果是属性注入但是作用域是proto

概述

循环依赖就是依赖关系形成环,比如最简单的循环依赖:a对象依赖b,b对象依赖a

属性注入与循环依赖

  1. 如果是构造器注入,如果循环依赖对象没法构建,因为还未实例化
  2. 如果是属性注入但是作用域是prototype,spring不会缓存其对象实例,也不能处理循环依赖的情况
  3. 如果是属性注入singleton的,其bean的实例化过程与属性注入过程是分开的,并且spring提供了三个map(就是大家说三级缓存)来实现。

spring属性注入处理循环依赖的方式

通过以下xml方式配置一个循环依赖的示例:

<bean id="person1" class="com.example.leetcode.spring.bean.person">
  <property name="parent" ref="person2"></property>
  <property name="name" value="tom"></property>
</bean>

<bean id="person2" class="com.example.leetcode.spring.bean.person">
  <property name="parent" ref="person1"></property>
  <property name="name" value="jack"></property>
</bean>

spring循环依赖处理几个关键位置:

获取bean对象

protected <t> t dogetbean(final string name, @nullable final class<t> requiredtype,
    @nullable final object[] args, boolean typecheckonly) throws beansexception {

  final string beanname = transformedbeanname(name);
  object bean;

  // 这里会检查单例bean是否已经在注册表,并返回。
  // eagerly check singleton cache for manually registered singletons.
  object sharedinstance = getsingleton(beanname);
  if (sharedinstance != null && args == null) {
    if (logger.istraceenabled()) {
      if (issingletoncurrentlyincreation(beanname)) {
        logger.trace("returning eagerly cached instance of singleton bean '" + beanname +
            "' that is not fully initialized yet - a consequence of a circular reference");
      }
      else {
        logger.trace("returning cached instance of singleton bean '" + beanname + "'");
      }
    }
    bean = getobjectforbeaninstance(sharedinstance, name, beanname, null);
  }
  ...
}

defaultsingletonbeanregistry(单例对象注册表)的几个关键属性。

  // 用来存储已经创建好的单例对象
  /** cache of singleton objects: bean name to bean instance. */
  private final map<string, object> singletonobjects = new concurrenthashmap<>(256);

  // 用来存储单例beanname到objectfactory的映射
  /** cache of singleton factories: bean name to objectfactory. */
  private final map<string, objectfactory<?>> singletonfactories = new hashmap<>(16);

  // 用来提前存储还未初始化好的单例对象
  /** cache of early singleton objects: bean name to bean instance. */
  private final map<string, object> earlysingletonobjects = new hashmap<>(16);

defaultsingletonbeanregistry.getsingleton()的实现.

protected object getsingleton(string beanname, boolean allowearlyreference) {
  object singletonobject = this.singletonobjects.get(beanname);
  if (singletonobject == null && issingletoncurrentlyincreation(beanname)) {
    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);
        }
      }
    }
  }
  return singletonobject;
}

abstractautowirecapablebeanfactory.docreatebean创建对象与注入属性

protected object docreatebean(final string beanname, final rootbeandefinition mbd, final @nullable object[] args)
      throws beancreationexception {
  ...
  instancewrapper = createbeaninstance(beanname, mbd, args);
  ...
  // 检查是否提前将单例bean存入缓存
  boolean earlysingletonexposure = (mbd.issingleton() && this.allowcircularreferences &&
    issingletoncurrentlyincreation(beanname));
  if (earlysingletonexposure) {
    if (logger.istraceenabled()) {
      logger.trace("eagerly caching bean '" + beanname +
          "' to allow for resolving potential circular references");
    }
    // 这里将beanname与工厂映射放入缓存注册表中(也就是上面的singletonfactories)
    addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean));
  }
  
  ...
  // 注入依赖属性
  populatebean(beanname, mbd, instancewrapper);
  ...
        
}

假设我们从beanfactory获取person1对象, 循环依赖处理流程如下:

1.通过abstractbeanfactory.dogetbean("persion1")获取对象

2.因为一开始通过defaultsingletonbeanregistry.getsingleton()什么都没有,进入abstractautowirecapablebeanfactory.docreatebean()进行创建

3.autowirecapablebeanfactory.docreatebean()里面执行完创建逻辑,因为是singleton将beanname与工厂的映射加入到addsingletonfactory()到缓存

4.开始处理person1对象的属性依赖populatebean()

5.当发现person1的parent属性是一个引用时,通过beanfactory.getbean("person2")获取依赖对象(org.springframework.beans.factory.support.beandefinitionvalueresolver#resolvereference)

6.此时进入person2的创建流程, person2也没有缓存,开始实例化并加入到addsingletonfactory()到缓存

7.person2在通过populatebean()注入属性依赖发现依赖person1, 此时通过beanfactory.getbean("person1")获取依赖对象

8.此时abstractbeanfactory.dogetbean("persion1")获取对象执行到getsingleton("person1")进行以下判断:

  • 从singletonobjects.get(beanname)获取到null
  • 进入if条件,对singletonobjects同步
  • 从earlysingletonobjects.get(beanname);获取也为null
  • 进入内层if,通过singletonfactories.get(beanname);获取到最开始bean实例化之后的beanname与工厂缓存信息
  • 获取到仅实例化完成的bean,并earlysingletonobjects.put(beanname, singletonobject);
  • 然后删除singletonfactories.remove(beanname);

9.此时从getsingleton("person1")返回了一个仅实例化尚未注入的bean引用

10.person2在第7步获取到person1仅实例化未注入的对象引用。

11.person2完成属性注入并返回。

12.person2被addsingleton(beanname, singletonobject);中singletonobjects.put(beanname, singletonobject)缓存,并删除singletonfactories.remove(beanname);earlysingletonobjects.remove(beanname);

13.person1在5步获取到person2的对象并完成属性注入

14.person1对象返回(因为一开始person2获取的是person1的引用,此时person1完成注入是能看到注入后的对象)

15.person1被addsingleton(beanname, singletonobject);中singletonobjects.put(beanname, singletonobject)缓存,并删除singletonfactories.remove(beanname);earlysingletonobjects.remove(beanname);

16.返回最终的person1对象

关于三个map(三级缓存)

在出现循环依赖时,三个map之间的流程如下:

先从singletonfactories获取工厂,并通过getobject获取对象并移除缓存,将对象缓存到earlysingletonobjects
通过earlysingletonobjects获取提前曝光的对象
对象创建并初始化完成之后,对象信息保留在singletonobjects并移除过earlysingletonobjects中的缓存

earlysingletonobjects二级缓存是鸡肋吗?

earlysingletonobjects缓存的目的是,通过三级缓存在获取对象会执行一些列的后置处理器,通过earlysingletonobjects来缓存提升性能。

以上就是spring解决循环依赖的详细内容,更多关于sping 循环依赖的资料请关注移动技术网其它相关文章!

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网