循环依赖

循环依赖

1、循环依赖的介绍

循环依赖,bean之间相互持有各自的引用,最终形成闭环。比如

QQ截图20180706104200.png

bean的实例化有如下三个步骤:

1、createBeanInstance ,生成原始对象

2、popoulateBean,进行属性注入

3、instantiateBean ,进行init-method初始化和后置处理

由此,当生成A对象之后,此时还未进行属性注入,检测到A有B属性,调用getBean(B b)获取B,

开始进行B的实例化,B生成对象之后,进行属性注入,检测到B有A属性,这个时候,就产生了循环依赖。

循环依赖会出现在下面几种情况:

1)构造函数的循环依赖

2)属性的循环依赖,分为单例和原型两种情况来分析

2、循环依赖的处理方式

2.1、单例的循环依赖

spring处理循环依赖是这样的:使用三级缓存。

/** Cache of singleton objects: bean name --> bean instance */
/** 缓存单例bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
/** 缓存单例bean的构造工厂 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name --> bean instance */
/** 缓存提前曝光的单例bean 即还未完成完整实例化的bean */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

这三级缓存分别是:

singletonObjects:单例对象工厂的cache,这里存储的是完整实例化之后的bean

singletonFactories:单例对象的ObjectFactory,该ObjectFactory返回的对象就是还未进行popoulateBean的原始对象

earlySingletonObjects:提前曝光的单例bean,就是已经本身还未进行属性注入的bean,已经作为其他的bean的属性注入到该bean中了,比如A还未进行属性注入,但是被B引用到了,注入到B中,此时就将A放到提前曝光的单例bean缓存earlySingletonObjects中。

针对单例进行源码分析:

假设A->B,B->A,以上bean对象存在循环依赖:

调用getBean(A)->AbstractBeanFactory.doGetBean(省略相关代码,留下关键代码)

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    //针对beanName进行处理
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //获取缓存的单例bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            //获取的bean当前处于创建状态,即还未初始化完成,仅仅是new出来而已,属性还没注入完成,且存在依赖循环
            //比如A->B,B->A
            //1、getBean(A),获取到A的实例,此时还未进行注入
            //2、开始注入,发现B属性,开始getBean(B),获取到B的实例
            //3、开始对B注入,发现A属性,获取到还未注入完成的A,即处于isSingletonCurrentlyInCreation的A
            //4、完成B的注入,getBean(B)完成,然后A的注入也完成,也就是在构建单例的时候,会将还未完成注入的A提前暴露,便于B完成注入
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //当用户输入的beanname前缀为“&”,要求获取的是factoryBean
        //否则获取的就是普通的bean
        //这里就是对这两种情况进行处理
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Create bean instance.
        //单例的处理
        //首先创建beanFactory,即ObjectBeanFacotry并实现getObject接口
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    // Explicitly remove instance from singleton cache: It might have been put there
                    // eagerly by the creation process, to allow for circular reference resolution.
                    // Also remove any beans that received a temporary reference to the bean.
                    destroySingleton(beanName);
                    throw ex;
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
    }

    return (T) bean;
}

由于A是第一次初始化,故会调用getSingleton方法:

sharedInstance = getSingleton(beanName, () -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      // Explicitly remove instance from singleton cache: It might have been put there
      // eagerly by the creation process, to allow for circular reference resolution.
      // Also remove any beans that received a temporary reference to the bean.
      destroySingleton(beanName);
      throw ex;
   }
});

这里调用的是DefaultSingletonBeanRegistry.getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   //锁定singletonObjects,确保线程安全
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         //对于正在创建状态的单例bean,再次进入此方法,抛出异常
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         //进行创建状态的记录 this.singletonsCurrentlyInCreation.add(beanName)
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            //进行创建状态的移除 this.singletonsCurrentlyInCreation.remove(beanName)
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            //将bean加载到对应的容器中,并对相关辅助容器进行bean的删除
            //this.singletonObjects.put(beanName, singletonObject);
            //this.singletonFactories.remove(beanName);
            //this.earlySingletonObjects.remove(beanName);
            //this.registeredSingletons.add(beanName);
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

这个方法一共做了这么几件事:

1、在创建实例之前,记录正在创建状态,singletonsCurrentlyInCreation.add(beanName)

2、创建实例,调用singletonFactory.getObject();

3、移除正在创建状态,this.singletonsCurrentlyInCreation.remove(beanName)

4、将该bean缓存到单例缓存容器, this.singletonObjects.put(beanName, singletonObject);并且从相关的辅助容器删除,如singletonFactories和earlySingletonObjects

进入到singletonFactory.getObject();,这里调用的是AbstractAutowireCapableBeanFactory.doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
         try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Post-processing of merged bean definition failed", ex);
         }
         mbd.postProcessed = true;
      }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   //如果当前是单例,且允许循环依赖而且当前bean处于创建状态
   //this.singletonFactories.put(beanName, singletonFactory);三级缓存添加实例对象工厂
   //this.earlySingletonObjects.remove(beanName);二级缓存删除实例对象
   //this.registeredSingletons.add(beanName);
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
         throw (BeanCreationException) ex;
      }
      else {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
      }
   }

   if (earlySingletonExposure) {
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
         }
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) {
               throw new BeanCurrentlyInCreationException(beanName,
                     "Bean with name '" + beanName + "' has been injected into other beans [" +
                     StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                     "] in its raw version as part of a circular reference, but has eventually been " +
                     "wrapped. This means that said other beans do not use the final version of the " +
                     "bean. This is often the result of over-eager type matching - consider using " +
                     "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
            }
         }
      }
   }

   // Register bean as disposable.
   try {
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

这个方法一共做了这么几件事:

1、实例化bean

  if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

2、如果当前允许循环依赖且当前bean是单例而且处于创建状态,将此单例的ObjectFactory加入到singletonFactories,且此factory返回的bean对象就是当前实例化好的bean

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

3、进行属性注入populateBean(beanName, mbd, instanceWrapper);

4、instantiateBean ,进行init-method初始化和后置处理

从这里可以看出来,在pupulateBean之前,singletonFactories存储了该bean的factory,然后进行pupulateBean,发现B是A的属性,然后调用getBean(B)对B进行实例化,重复上面的步骤到B的属性注入环节,发现A是B的属性,这个时候,再次调用getBean(A),此时缓存中已经有了A了

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

   //针对beanName进行处理
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   //获取缓存的单例bean
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         //获取的bean当前处于创建状态,即还未初始化完成,仅仅是new出来而已,属性还没注入完成,且存在依赖循环
         //比如A->B,B->A
         //1、getBean(A),获取到A的实例,此时还未进行注入
         //2、开始注入,发现B属性,开始getBean(B),获取到B的实例
         //3、开始对B注入,发现A属性,获取到还未注入完成的A,即处于isSingletonCurrentlyInCreation的A
         //4、完成B的注入,getBean(B)完成,然后A的注入也完成,也就是在构建单例的时候,会将还未完成注入的A提前暴露,便于B完成注入
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      //当用户输入的beanname前缀为“&”,要求获取的是factoryBean
      //否则获取的就是普通的bean
      //这里就是对这两种情况进行处理
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   return (T)bean;
 }

重点关注

   //获取缓存的单例bean
   Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   /** 从singletonObjects获取bean实例 */
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         /** 如果singletonObjects还没有此bean,有两种情况
          * 1、说明还未完全实例化,正在创建状态,先从earlySingletonObjects获取
          * 2、该bean还没开始创建
          */
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            /** 如果earlySingletonObjects还没有此bean,有两种情况
             * 1、说明还未曝光,即被其他bean注入,正在创建状态,先从singletonFactories获取
             * 2、该bean还没开始创建*/
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               /** factory不为空,说明处于正在创建状态,且还未被其他bean注入,从singletonObject取出bean
                * 1、将此bean放到提前曝光的缓存earlySingletonObjects中
                * 2、同时删除在singletonFactories的缓存
                * */
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

这个方法做了这么一件事,逐步从三级缓存中获取bean:

1)先到singletonObjects获取,如果有表示实例化已经完成;

2)否则到earlySingletonObjects获取,如果有表示已经有bean,且存在循环依赖,将此bean作为属性注入了

3)否则到singletonFactories获取,如果存在循环依赖,且此属性是第一次被其他bean作为属性注入

这里B将A第一次作为属性注入,返回的是singletonFactories生成的bean,也就是刚刚未完成实例化的A对象。

此时A的引用从singletonFactories转移到earlySingletonObjects,表示已经被曝光了。

此时B已经完成属性注入,到这里,其实B已经完成了实例化,也可以说A完成了属性注入了。

接下来回顾获取A的这个方法DefaultSingletonBeanRegistry.getSingleton,其实到了这里,我们也只是完成了singletonFactory.getObject(),最后一步,将A放在singletonObjects中:

 //将bean加载到对应的容器中,并对相关辅助容器进行bean的删除
 //this.singletonObjects.put(beanName, singletonObject);
 //this.singletonFactories.remove(beanName);
 //this.earlySingletonObjects.remove(beanName);
 //this.registeredSingletons.add(beanName);
 addSingleton(beanName, singletonObject);

至此,单例的循环依赖得到了解决。

其实,解决循环依赖就在于未完成实例化的Bean在三级缓存中的转移:

1)A刚实例化,未进行属性注入,添加到singletonFactories

2)正在属性注入B,且同时第一次被B所依赖,B在属性注入的时候将A由singletonFactories转移至earlySingletonObjects

3)待B属性注入完成,完成实例化,A也就完成了实例化,此时,将A转移至singletonObjects

同理,B亦是如此

2.2、构造方法的循环依赖

由于此循环依赖是在对象实例化的时候进行的,也就是说这种依赖是无法像单例一样生成对象,那么这种循环依赖也只能通过抛出异常处理

2.3、原型模式的循环依赖

由于原型模式不像单例一样会提供缓存来进行辅助存储未完整实例化的bean,故spring的处理也是直接抛出异常

//对于原型模式的循环依赖,直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容