Spring 循环依赖

文章详细介绍了Spring框架在处理Bean对象循环依赖时的机制,包括Bean的生命周期、三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)的作用,以及如何通过这些缓存解决循环依赖问题。在创建Bean过程中,Spring会先创建原始对象并存入三级缓存,当遇到依赖时,尝试从缓存中获取,如果发现循环依赖,则利用ObjectFactory获取早期引用,完成依赖注入,最后将完全初始化的Bean放入一级缓存。此外,文章还提到了AOP在解决循环依赖中的作用。
Spring 循环依赖概念

在Spring容器中,对Bean对象的创建并不是简单的new出来就完成,而是会经过一系列的Bean的生命周期,就是因为Bean的生命周期所以才会出现循环依赖的问题,比如:Spring在创建一个AService Bean对象,AService经过Bean的生命周期,在进行属性注入(依赖注入)时需要注入BService,此时会去Spring容器的单例池中查找BService对象,如果此时单例池没有BServcie对象,Spring容器则去创建BService的Bean对象,在创建BService Bean对象,经过Bean的生命周期,在进行属性注入(依赖注入)时,BService有个属性AService,需要注入AService对象而AService对象正在创建过程中,此时就出现了循环依赖的问题。

在Spring中,出现循环依赖的场景很多,有的场景Spring自动帮我们解决了,而有的场景则需要程序员来解决。
Spring 三级缓存解决循环依赖

在Spring中,采用三级缓存的机制来帮助开发者解决了部分循环依赖的问题,三级缓存是一个通用的叫法,三级缓存分为以下三种Map:

  • 一级缓存:singletonObjects

  • 二级缓存:earlySingletonObjects

  • 三级缓存:singletonFactories

解决思路分析

上述场景出现的循环依赖,Spring解决思路分析

  • Spring在创建AServicce对象时,会先实例化一个AService的原始对象,使用AService的原始对象去生成一个ObjectFactory,这个ObjectFactory就是一个lambda表达式(() -> getEarlyBeanReference(beanName, mbd, bean)),将这个ObjectFactory对象存入singletonFactories(三级缓存),此时并不会执行lambda表达式即不会执行getEarlyBeanReference方法。

  • AService对象在进行属性赋值(依赖注入)时,需要给bService属性注入BService对象值,首先从Spring容器的单例池中找BService对象,没有找到,则创建BService对象,在进行创建BService Bean的生命周期中进行依赖注入,此时需要注入aService属性值。

  • 从singletonFactories中获取beanName对应的ObjectFactory,然后执行ObjectFactory,也就是执行getEarlyBeanReference方法,此时会得到AService原始对象经过AOP之后的代理对象,把代理对象放入earlySingletonObjects(二级缓存)中。继续执行BService Bean对象的生命周期步骤,完成BService对象的创建。

  • 当BService对象创建完成后,AService对象继续进行生命周期,在AService对象完成属性注入后,会按照本身的逻辑进行AOP,而此时的AService对象已经经历了AOP,Spring底层会利用earlyProxyReferences,去判断当前beanName是否在earlyProxyReferences,如果在则表示提前进行了AOP了,无需再次进行AOP。

  • 对于AService而言,进行了AOP的判断后及BeanPostProcessor的执行之后,就需要把AService对应的对象放入singletonObjects(一级缓存)单例池中,所以此时需要从earlySingletonObjects中得到代理对象,然后放入singletonObjects中。

Spring 解决循环依赖实现源码
AService 原始对象创建

AService对象创建,经过Bean生命周期,将AService对象正在创建beanName缓存到Set alreadyCreated中,实例化得到一个AService的原始对象,实现源码位于 AbstractAutowireCapableBeanFactory#doCreateBean

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

   // 实例化bean
   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      // 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      // 创建Bean实例
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
      mbd.resolvedTargetType = beanType;
   }

   // 后置处理合并后的BeanDefinition
   // 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.
   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)) {
            // beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
            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 " +
                     "'getBeanNamesForType' 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;
}
ObjectFactory添加到singletonFactories

利用AService的原始对象生成一个ObjectFactory(是一个lambda表达式,具有getEarlyBeanReference方法),将这个ObjectFactory缓存在singletonFactories(三级缓存)

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);
      }
   }
}
AService 属性依赖注入

AService Bean对象进入依赖注入的生命周期步骤,此时需要对BService属性值进行赋值,会拿BService这个名字去Spring容器(单例池)中查找,没找到,则进行BService对象的创建,具体实现源码位于AbstractAutowireCapableBeanFactory#populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   //......
   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         // 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值
         // AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了
         PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   // 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired
   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

调用AutowiredAnnotationBeanPostProcessor#postProcessProperties方法查找注入点

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   // 找注入点(所有被@Autowired注解了的Field或Method)
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;
}

调用InjectionMetadata#jinect方法遍历所有的注入点依赖注入,注入点可能是:AutowiredFieldElement、AutowiredMethodElement,具体可看Spring Bean依赖注入。

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   Collection<InjectedElement> checkedElements = this.checkedElements;
   Collection<InjectedElement> elementsToIterate =
         (checkedElements != null ? checkedElements : this.injectedElements);
   if (!elementsToIterate.isEmpty()) {
      // 遍历每个注入点进行依赖注入
      for (InjectedElement element : elementsToIterate) {
         element.inject(target, beanName, pvs);
      }
   }
}
BService 原始对象创建

在AService对象进行属性注入时存在BService属性,需要获取BService对象,Spring底层实现中先从单例池获取BService对象,如果不存在,则创建BService对象,Spring进行BService创建的生命周期,创建得到一个BService的原始对象,其底层实现和AService原始对象创建、ObjectFactory添加到singletonFactories一致,只是创建的Bean对象不同。

BService 属性依赖注入

BService对象生命周期进入依赖注入步骤,BService对象拥有AService的属性,这时Spring在单例池获取AService对象时,getSingleton(String beanName,boolean allowEarlyReference)中进行判断获取AService对象是否在创建中,此时就能判断出bean是否出现了循环依赖。Spring底层实现源码入口位于AbstractBeanFactory#doGetBean方法

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

   // name有可能是 &xxx 或者 xxx,如果name是&xxx,那么beanName就是xxx
   // name有可能传入进来的是别名,那么beanName就是id
   String beanName = transformedBeanName(name);
   Object beanInstance;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   //......
}

上面的getSingleton(beanName)方法会调用DefaultSingletonBeanRegistry#getSingleton方法

public Object getSingleton(String beanName) {
   return getSingleton(beanName, true);
}

在下面方法源码中,会从singletonFactories(三级缓存)中获取AService的ObjectFactory对象,调用getObject()方法会执行lambda表达式中的getEarlyBeanReference方法。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                      //执行lambda表达式中的getEarlyBeanReference方法
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

getEarlyBeanReference方法调用,源代码位于AbstractAutowireCapableBeanFactory#getEarlyBeanReference

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
         exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
      }
   }
   return exposedObject;
}

最终调用AbstractAutoProxyCreator#getEarlyBeanReference方法,在此方法类会将beanName缓存在earlyProxyReferences中,调用wrapIfNecessary方法进行是否需要进行AOP,如果需要进行AOP,会进行AOP操作生成代理对象,不需要进行AOP则直接返回原始对象。

public Object getEarlyBeanReference(Object bean, String beanName) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   this.earlyProxyReferences.put(cacheKey, bean);
   return wrapIfNecessary(bean, beanName, cacheKey);
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }

   // advisedBeans表示已经判断过了的bean,false表示此bean不需要进行Aop
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }

   // 当前正在创建的Bean不用进行AOP,比如切面Bean
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // Create proxy if we have advice.
   // 判断当前bean是否存在匹配的advice,如果存在则要生成一个代理对象
   // 此处根据类以及类中的方法去匹配到Interceptor(也就是Advice),然后生成代理对象,代理对象在执行的时候,还会根据当前执行的方法去匹配
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      // advisedBeans记录了某个Bean已经进行过AOP了
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}
循环依赖解决完毕

BService对象生命周期依赖注入步骤完成后,进行后续的生命周期操作步骤,最终将BService创建的Bean对象放入Spring的singletonObjects(单例池)中,AService对象完成属性注入后,继续进行后续的生命周期,在进行初始化之后的步骤,会按照本身的逻辑去进行AOP,此时AService对象已经经历了AOP操作,那么在postProcessAfterInitialization方法中会去判断earlyProxyReferences缓存中是否存在AService的key,如果存在表示已经进行了AOP,无需再次进行AOP。Spring底层实现源码位于AbstractAutoProxyCreator#postProcessAfterInitialization方法中。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

对于AService对象而言,进行了AOP的判断及BeanPostProcessor的执行之后,就需要把AService对应的对象放入singletonObjects(单例池)中,所以此时需要从earlySingletonObjects(二级缓存)中得到代理对象,然后放入singletonObjects中。此时整个循环依赖解决完毕。Spring底层实现源码位于AbstractAutowireCapableBeanFactory#doCreateBean方法中

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   //......
   if (earlySingletonExposure) {
       Object earlySingletonReference = getSingleton(beanName, false);
       if (earlySingletonReference != null) {
          if (exposedObject == bean) {
             exposedObject = earlySingletonReference;
          }
          else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
             // beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错
             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 " +
                      "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
             }
          }
       }
    }
    //......
}
总结

Spring采用三级缓存的机制解决了循环依赖的问题,对三级缓存进行总结:

  • singletonObjects:缓存经过了完整生命周期的bean。

  • earlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects,但是不管怎么样,就是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整生命周期的bean。

  • singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。

  • earlyProxyReferences:一个缓存用来记录某个原始对象是否进行过AOP了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值