Spring如何解决循环依赖的问题

1 篇文章 0 订阅
1 篇文章 0 订阅

1、何为循环依赖?

循环依赖就是两个bean或者两个以上互相调用对方,是对象之间的相互依赖关系,最终形成一个闭环。如下图

2、spring中的几种bean的注入方式

  • 构造器注入

首先我们创建如下两个类PeopleA 和PeopleB

package com.test.tools;

public class PeopleA {
    private PeopleB peopleB;
    public PeopleA() {

    }
    public PeopleA(PeopleB peopleB) {
        this.peopleB = peopleB;
    }
    public void setPeopleB(PeopleB peopleB) {
        this.peopleB = peopleB;
    }
}
package com.test.tools;

public class PeopleB {
    private PeopleA peopleA;
    public PeopleB() {

    }
    public PeopleB(PeopleA peopleA) {
        this.peopleA = peopleA;
    }
    public void setPeopleA(PeopleA peopleA) {
        this.peopleA = peopleA;
    }
}

PeopleA中的有参构造为PeopleB,PeopleB中的有参构造为PeopleA,这样就构成了循环依赖的情况,配置如下xml让交给Spring去管理

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="peopleA" class="com.test.tools.PeopleA" >
        <constructor-arg index="0" ref="peopleB"></constructor-arg>
    </bean>
    <bean id="peopleB" class="com.test.tools.PeopleB" >
        <constructor-arg index="0" ref="peopleA"></constructor-arg>
    </bean>
</beans>

测试类代码:

package com.test.tools;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PeopleTest {
    public static void main(String[] args) {
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
         System.out.println(context.getBean("peopleA", PeopleA.class));
         System.out.println(context.getBean("peopleB", PeopleB.class));
    }
}

测试结果:抛出了

org.springframework.beans.factory.BeanCurrentlyInCreationExceptiony异常

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'peopleA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'peopleB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'peopleB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'peopleA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'peopleA': Requested bean is currently in creation: Is there an unresolvable circular reference?

spring容器首先去创建单例PeopleA,然而PeopleA依赖了PeopleB,然后去创建PeopleB,然而PeopleB又依赖了PeopleA,由于构造器的注入是在实例化对象的时候通过反射调用构造器去注入对象的,这样会导致PeopleA和PeopleB永远都无法拿到完整创建好的Bean,导致循环调用无法退出,所以构造器方式无法解决循环依赖的问题

  • setter方式注入

将上面的xml配置文件改成setter单例模式

 

 

 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="peopleA" class="com.test.tools.PeopleA">
        <property name="peopleB" ref="peopleB"/>
    </bean>
    <bean id="peopleB" class="com.test.tools.PeopleB">
        <property name="peopleA" ref="peopleA"/>
    </bean>
</beans>

 

在执行测试类,得到如下结果:

 

 

com.test.tools.PeopleA@f6c48ac
com.test.tools.PeopleB@13deb50e

 

setter方式未出现循环依赖的问题,Spring对于循环依赖的问题是采用缓存的方式,我们先来看下DefaultSingletonBeanRegistry这个类中的几个方法

 

 

/** Cache of singleton objects: bean name --> bean instance */
  /**单例对象的cache,用于存储完整的Bean,称之为一级缓存*/
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

  /** Cache of early singleton objects: bean name --> bean instance */
  /**用于存储不完整的Bean,可能是直接new出来的,还没有填充属性的Bean,称之为二级缓存 **/
  private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
  
  /** Cache of singleton factories: bean name --> ObjectFactory */
  /**单例对象工厂的cache,用于存储Bean的工厂对象,称之为三级缓存*/
  private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

 

循环依赖是发生在获取Bean时,我们直接来调试下AbstractBeanFactory这个类中的doGetBean这个方法,看下源码:

protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException{
    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()) {
        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 + "'");
        }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }else {
      //未获取到执行以下代码
      ....//省略,如果需要请自行查看源码

      try {
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);
        // Guarantee initialization of beans that the current bean depends on.
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
          ....//省略,如果需要请自行查看源码
        }
        // Create bean instance. 
        //如果是单例的Bean则下面的代码
        if (mbd.isSingleton()) {
          sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {
              try {
                // 创建单例Bean的方法,返回的bean是完整的
                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);
        }else if (mbd.isPrototype()) {
          ....//省略,如果需要请自行查看源码
        }else {
          ....//省略,如果需要请自行查看源码
        }
      }
      catch (BeansException ex) {
        cleanupAfterBeanCreationFailure(beanName);
        throw ex;
      }
    }
    ....//省略,如果需要请自行查看源码
    return (T) bean;
  }
Object sharedInstance = getSingleton(beanName);

方法内部调用了

getSingleton(beanName, true);

看下该方法的源码:

/**
   * Return the (raw) singleton object registered under the given name.
   * <p>Checks already instantiated singletons and also allows for an early
   * reference to a currently created singleton (resolving a circular reference).
   * @param beanName the name of the bean to look for
   * @param allowEarlyReference whether early references should be created or not
   * @return the registered singleton object, or {@code null} if none found
   */
  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从一级缓存中获取单例的Bean
    Object singletonObject = this.singletonObjects.get(beanName);
    //如果一级缓存中没有获取到对象或者这个Bean正在创建中
    //isSingletonCurrentlyInCreation 用来判断这个Bean是否还没初始化完成,也就是还在创建的过程中
    //犹如上面的说的,PeopleA依赖的PeopleB,得先去创建PeopleB,
    //或者说PeopleA在填充属性的时候(populateBean)发现依赖了PeopleB,得先去创建PeopleB
    //那么此时的PeopleA就是属于创建中的状态
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        //从二级缓存中获取单例的bean
        singletonObject = this.earlySingletonObjects.get(beanName);
        //allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象
        if (singletonObject == null && allowEarlyReference) {
          //从三级缓存中获取单例的Bean
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          if (singletonFactory != null) {
            //通过单例工厂获取到了单例的Bean,三级缓存被取出保存为bean之后
            //就会想三级缓存放入到二级缓存,同时清空三级缓存
            singletonObject = singletonFactory.getObject();
            //将三级缓存移动到二级缓存,
            this.earlySingletonObjects.put(beanName, singletonObject);
            //将三级缓存清空
            this.singletonFactories.remove(beanName);
          }
        }
      }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
  }

此时已经获取了sharedInstance如果不为空,那么就直接返回了,但如果他为空并且为单例模式呢?可以看出它调用了以下方法

getSingleton(String beanName, ObjectFactory<?> singletonFactory)
/**
   * Return the (raw) singleton object registered under the given name,
   * creating and registering a new one if none registered yet.
   * @param beanName the name of the bean
   * @param singletonFactory the ObjectFactory to lazily create the singleton
   * with, if necessary
   * @return the registered singleton object
   */
  public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "'beanName' must not be null");
    synchronized (this.singletonObjects) {
      //从一级缓存中获取单例的Bean
      Object singletonObject = this.singletonObjects.get(beanName);
      //从一级缓存中获取的结果为空
      if (singletonObject == null) {
        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 + "'");
        }
        //将beanName添加到set集合中Set<String> singletonsCurrentlyInCreation
        //将BeanName暴露出去
        beforeSingletonCreation(beanName);
        boolean newSingleton = false;
        boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
        if (recordSuppressedExceptions) {
          this.suppressedExceptions = new LinkedHashSet<Exception>();
        }
        try {
          //创建单例的Bean
          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;
          }
          afterSingletonCreation(beanName);
        }
        if (newSingleton) {
          //将新创建的Bean添加到一级缓存中,并且删除其他缓存
          addSingleton(beanName, singletonObject);
        }
      }
      return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
  }

接下来看下addSingleton方法

addSingleton(String beanName, Object singletonObject)
/**
   * Add the given singleton object to the singleton cache of this factory.
   * <p>To be called for eager registration of singletons.
   * @param beanName the name of the bean
   * @param singletonObject the singleton object
   */
  protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
      //将新Bean添加到一级缓存中,
      this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
      //删除三级缓存
      this.singletonFactories.remove(beanName);
      //删除二级缓存
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
    }
  }

从之前的源码可以看出,bean最终的创建逻辑是由

createBean(String beanName, RootBeanDefinition mbd, Object[] args)

里的

doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)

完成的

/**
   * Actually create the specified bean. Pre-creation processing has already happened
   * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
   * <p>Differentiates between default bean instantiation, use of a
   * factory method, and autowiring a constructor.
   * @param beanName the name of the bean
   * @param mbd the merged bean definition for the bean
   * @param args explicit arguments to use for constructor or factory method invocation
   * @return a new instance of the bean
   * @throws BeanCreationException if the bean could not be created
   * @see #instantiateBean
   * @see #instantiateUsingFactoryMethod
   * @see #autowireConstructor
   */
  protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
      throws BeanCreationException {

    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
      //从factoryBeanInstanceCache中获取缓存的BeanWrapper(bean的包装类)并从中移除
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
      // 根据指定bean使用对应的策略创建新的实例,如:工厂方法、构造函数自动注入等
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 实例化后的Bean对象,这里是还没有进行属性填充的对象
    final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
    Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    mbd.resolvedTargetType = beanType;

    // Allow post-processors to modify the merged bean definition.
    synchronized (mbd.postProcessingLock) {
      if (!mbd.postProcessed) {
        try {
          //应用MergedBeanDefinitionPostProcessor
          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正在创建中,检测循环依赖
    //如果没有循环依赖的情况,是不会有二级和三级缓存的
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
    // 如果需要提前暴露单例bean,则将该bean工厂放入三级缓存中
    if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
        logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");
      }
      // 将刚创建的bean工厂放入三级缓存中singleFactories,同时会移除二级缓存对应的Bean
      addSingletonFactory(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
          return getEarlyBeanReference(beanName, mbd, bean);
        }
      });
    }
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
      //填充Bean的属性,依赖注入
      populateBean(beanName, mbd, instanceWrapper);
      if (exposedObject != null) {
        //调用初始化方法,完成bean的初始化操作
        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<String>(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;
  }

现在重新梳理下之前说到的A依赖B,B依赖A的问题是如何解决的?

1、调用doGetBean()方法,尝试着去获取beanA,通过此方法getSingleton(String beanName, boolean allowEarlyReference)从一级缓存中去获取如果获取为空,通过getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法将beanA的name放入到一个set集合(Set<String> singletonsCurrentlyInCreation)中,用来标记beanA正在创建中

2、调用AbstractAutowireCapableBeanFactory内部类doCreateBean(),通过反射调用构造器创建实例beanA,通过判断条件(单例并且允许循环依赖并且当前bean正在创建中并且检测循环依赖)将其翻入到三级缓存中

3、然后开始populateBean填充beanA的属性,发现需要依赖beanB(第一第二步),此时又发现beanB依赖了beanA,通过一二三级缓存中查找发现三级缓存中获取到了beanA的创建工厂,进而获取到singletonObject,这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中,beanA继续populateBean,此时已经获取到了beanB,beanA也随之完成了创建,回到getSingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中,同时也完成了beanA的初始化。

更多请关注公众号,若存在问题,麻烦指正

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值