面试官:小兄弟,Spring是怎么解决循环依赖的呢?

Spring的源码错综复杂,并且类名一般都比较长,并且调用层次较深。因此阅读起来有一定的难度,所以阅读的时候可以先从大体上理解整个流程,而不需要逐行的阅读。不然很容易陷入细节而无法自拔,导致事倍功半。
在深入Spring源码之前,需要先了解几个非常重要的接口,理解他们,是理解Spring容器启动的关键。
核心接口

BeanDefinition

BeanDefinition是Spring中非常重要的一个接口,定义于spring-beans模块中,其定义如下:

/**
 * A BeanDefinition describes a bean instance, which has property values,
 * constructor argument values, and further information supplied by
 * concrete implementations.
 *
 * <p>This is just a minimal interface: The main intention is to allow a
 * {@link BeanFactoryPostProcessor} to introspect and modify property values
 * and other bean metadata.
 *
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
}

根据接口描述,我们可以知道
BeanDefinition描述了一个bean实例,它具有属性值,构造函数参数值以及具体实现提供的更多信息。
看完类的描述,我们似乎依然不知道这个接口是用来干嘛的。

就我自己的理解,BeanDefinition主要做用是定义了一个Spring Bean的元信息(metadata)的抽象。使得不管是XML文件配置的Spring Bean、注解扫描的Spring Bean,还是Java Config类配置Spring Bean,都能一个统一的抽象来表示,这个抽象就是BeanDef

doCreateBean
该方法用于创建Spring Bean,经过层层套娃,终于来到了重点,该方法定义如下

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.
 // 此处是Spring解决循环引用的关键
 // 第一个条件判断当前bean是否是单例,也就说明Spring只支持单例Bean的循环引用
 // 第二个条件默认是true,也就说Spring默认是支持循环引用的,如果想要关闭循环引用,把这个值设置成false即可
 // 第三个条件就是判断当前bean是否正在被创建,由于之前已经调用过beforeSingletonCreation方法,所以这个条件为true
 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.
 // 初始化bean实例
 Object exposedObject = bean;
 try {
  // 填充属性,也就是自动注入
  populateBean(beanName, mbd, instanceWrapper);
  // 真正的初始Spring 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<>(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;
}

解决循环依赖的关键就是在第一步和第二步之间,判断当前bean是否需要支持循环引用,如果需要,就提前暴露出去,这时候暴露出去的bean是尚未完成初始化的bean,也就是所谓的半成品。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值