Spring循环依赖如何解决

所谓的循环依赖就是在Spring IOC容器实例化对象的时候,有两个后者以上的对象互相依赖对方,持有对方的引用并且需要完成注入的情况,那么对于这种循环依赖,Spring是如何处理的呢,首先我在代码里面构建环境依赖

package com.xp.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class F {

   @Autowired
   private O o;
}
package com.xp.config;


import org.springframework.context.annotation.*;

@Configuration
@ComponentScan("com.xp")
@EnableAspectJAutoProxy
public class AppConfig {

}
package com.xp.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class O {

   @Autowired
   private F f;

}

运行main方法程序正常打印了o对象,并没有报错

Spring循环依赖如何解决

那么spring是如何解决循环依赖的呢,我们用idea断点进去看源码的流程

Spring循环依赖如何解决

 

Spring循环依赖如何解决

 

Spring循环依赖如何解决

首先创建f对象的时候会进入getBean方法去容器里面拿是否已经缓存了该bean对象,我们跟进这个getSingleton方法里面

Spring循环依赖如何解决

可以看到在这个方法里面有三个map singletonObjects,singletonFactories,earlySingletonObjects,第一个是用来存放容器实例化后的单例对象,也可以说是单例池,第二个单例工厂对象池,第三个是提前暴露的对象池

Spring循环依赖如何解决

 

第一次从单例池没有拿到f这个bean对象,然后开始调用creatbean来创建f对象Spring循环依赖如何解决

接着会调用doCreateBean来完成f对象的实例化

/**
 * 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 @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 {
            //第三次调用bean后置处理器判断是否需要合并bean
            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.
   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");
      }
      //第四次调用后置处理器
      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;
}
/**
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

在这里面完成f的实例化,会调用一个addSingletonFactory方法在里面将这个实例化的f对象放到上面提到的缓存工厂map里面,然后,开始来为这个f对象来初始化设置属性,也就是会调用下面这个方法

populateBean(beanName, mbd, instanceWrapper);

在这个方法里面为f对象设置属性的时候,spring会判断f对象引用的o对象是否存在,也就是会接着f对象的创建从新走一遍上面的

getBean,o在初始化第一步的时候发现自己依赖了对象f,于是尝试getBean(f),尝试缓存singletonObjects里面去获取,这个时候这个单例池肯定是还没有值得,因为f对象还不是一个完整的对象,属性并没有初始化完成,还没有放到这个一级缓存singletonObjects里面,然后会从尝试从earlySingletonObjects二级缓存里面获取,也没有,接着尝试从三级缓存singletonFactories里获取,由于支付f对象实例化完成后调用addSingletonFactory方法将f这个对象提前放到了三级缓存singletonFactories里面,所以此时o对象能够通缓存里面的ObjectFactory.getObject拿到f对象,完成属性的注入,然后完成spring其他生命周期的流程,将一个完整的o对象放到一级缓存singletonObjects里面,最终回到f对象这里,f也能拿到他的成员属性o对象,完成属性注入,最终完成了f对象的生命周期流程,也就解决了循环依赖的问题,但是spring无法解决通过构造方法形式注入的循环依赖,因为放入缓存池的操作是必须对象实例化以后,所以spring是无法解决构造方法和原型模式的循环依赖问题