循环依赖

作者: liu_c02c | 来源:发表于2018-07-06 14:12 被阅读714次

    循环依赖

    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);
    }
    

    相关文章

      网友评论

        本文标题:循环依赖

        本文链接:https://www.haomeiwen.com/subject/reovuftx.html