Spring源码系列(四)——Bean的循环依赖注入报错流程分析

上一篇文章我们介绍了Bean的实例化过程以及相互依赖注入的情况,本篇我们介绍一下循环依赖注入报错。
首先我们要改一下StudentA和StudentB的代码,具体如下:
在这里插入图片描述
在这里插入图片描述
可以看到在两个类中构造方法都注入了彼此,接着我们断点看一下代码的执行流程。
首先执行到StudentA的doCreateBean
在这里插入图片描述
此时缓存中没有StudentA实例,直接走到getSingleton方法
在这里插入图片描述
然后走到方法中的beforeSingletonCreation方法
在这里插入图片描述
将beanName保存在singletonsCurrentlyInCreation中,标识此beanName对应的对象正在实例化中。
在这里插入图片描述
在这里插入图片描述
接着调用createBean方法调到doCreateBean中
在这里插入图片描述
然后进入createBeanInstance方法中初始化StudentA实例

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   // 获取class对象
   Class<?> beanClass = resolveBeanClass(mbd, beanName);
   ... ...
   // Candidate constructors for autowiring?
   // 1.判断是否有@AutoWrite的构造方法
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   // 判断是否有默认构造方法
   ctors = mbd.getPreferredConstructors();
   if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   // 使用无参构造方法进行实例化
   return instantiateBean(beanName, mbd);
}

由于我们StudentA中有@Autowired注解的构造方法,所以会通过注释第1点处的判断,进入到autowireConstructor方法中
在这里插入图片描述

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
      @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
      ... ...
      // 对所有构造方法进行排序
      AutowireUtils.sortConstructors(candidates);
      int minTypeDiffWeight = Integer.MAX_VALUE;
      Set<Constructor<?>> ambiguousConstructors = null;
      LinkedList<UnsatisfiedDependencyException> causes = null;

      for (Constructor<?> candidate : candidates) {
         // 获取构造方法参数类型
         Class<?>[] paramTypes = candidate.getParameterTypes();

         if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
            // Already found greedy constructor that can be satisfied ->
            // do not look any further, there are only less greedy constructors left.
            break;
         }
         if (paramTypes.length < minNrOfArgs) {
            continue;
         }

         ArgumentsHolder argsHolder;
         if (resolvedValues != null) {
            try {
               String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
               if (paramNames == null) {
                  ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                  if (pnd != null) {
                     // 获取构造方法参数名称
                     paramNames = pnd.getParameterNames(candidate);
                  }
               }
               // 1.获取构造方法中的参数实例对象
               argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                     getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
            }
            ... ...
         }
         ... ...
   }
   Assert.state(argsToUse != null, "Unresolved constructor arguments");
   bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
   return bw;
}

此时会在createArgumentArray方法这里准备好调用构造方法时用到的所有参数值,StudentA的构造方法中的studentB对象就是在这里进行实例化,我们接着往下看

private ArgumentsHolder createArgumentArray(
      String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
      BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
      boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {

     ... ...
         try {
            // 获取@AutoWired注解的构造方法中的参数实例
            Object autowiredArgument = resolveAutowiredArgument(
                  methodParam, beanName, autowiredBeanNames, converter, fallback);
            args.rawArguments[paramIndex] = autowiredArgument;
            args.arguments[paramIndex] = autowiredArgument;
            args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
            args.resolveNecessary = true;
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(
                  mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
         }
    ... ...
   return args;
}

在这里插入图片描述
最后走到我们之前分析BeanFactory实例化@Autowired注解的类属性一样的流程。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后走到BeanFactory的getBean方法,开始进行StudentB的实例化流程。
所以接下来就会走到StudentB的doGetBean方法
在这里插入图片描述
此时缓存中没有StudentB实例,跟StudentA一样,继续往下走到getSingleton方法
在这里插入图片描述
同样的,在getSingleton里的beforeSingletonCreation方法中标识studentB处于正在实例化中。
在这里插入图片描述
此时可以看到singletonsCurrentlyInCreation中有存在两个正在实例化中的对象
在这里插入图片描述
接着继续调用到了createBean方法
在这里插入图片描述
来到了doCreateBean方法
在这里插入图片描述
然后接下来的流程就跟StudentA的一样,此时StudentB也会走到使用@AutoWrite的构造方法创建实例这里
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时获取到StudentB构造方法中的StudentA参数,开始对StudentA进行实例化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后走到BeanFactory的getBean方法
在这里插入图片描述
所以接下来BeanFactory会调用doGetBean方法再一次开始StudentA的实例化,从这里我们可以发现,前面的流程中的StudentA和StudentB目前扔处于获取构造方法参数值的阶段中,还没有达到调用构造方法创建实例的条件。
我们接着继续看一下doGetBean方法
在这里插入图片描述
此时缓存中也没有StudentA实例,所以继续往下走
在这里插入图片描述
在这里插入图片描述
此时进入到beforeSingletonCreation方法中
在这里插入图片描述
由于singletonsCurrentlyInCreation集合已经存在studentA,所以this.singletonsCurrentlyInCreation.add(beanName)将会返回false,此时就进入if方法体中,抛出了循环依赖的异常。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值