【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析(下)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析(下)

ConstructorResolver#autowireConstructor


这个方法作用是获取被包装后的bean,包装后的对象是BeanWrapper对象,这个对象的实现类是BeanWrapperImpl。其中包含被封装后待处理的bean,和设置bean属性的属性编辑器。


  protected BeanWrapper autowireConstructor(
      String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
    // 此处的this,就是DefaultListableBeanFactory嘛
    return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
  }
// ConstructorResolver#autowireConstructor
  public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
      @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
    //先实例化一个BeanWrapperImpl类对象
    BeanWrapperImpl bw = new BeanWrapperImpl();
    // initBeanWrapper做了一些事,比如注册解析器、value解析器等等  这是个比较大的概念,后面会有专题再说吧
    this.beanFactory.initBeanWrapper(bw);
    Constructor<?> constructorToUse = null;
    ArgumentsHolder argsHolderToUse = null;
    Object[] argsToUse = null;
     //如果构造参数不为空就直接使用这些参数即可
    if (explicitArgs != null) {
      argsToUse = explicitArgs;
    }
    // 否则构造函数的入参,交给Spring处理。它会去容器里拿~~~~~
    else {
      Object[] argsToResolve = null;
      synchronized (mbd.constructorArgumentLock) {
        //获取已缓存解析的构造函数或工厂方法(resolvedConstructorOrFactoryMethod----用于缓存已解析的构造函数或工厂方法)
                constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
        如果缓存不为空,并且构造参数已经解析缓存了,(constructorArgumentsResolved为包可见,用于表示构造参数状态是否已经解析)
        // 显然首次进来,都是为null并且没有被解析的
        constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
        if (constructorToUse != null && mbd.constructorArgumentsResolved) {
          // Found a cached constructor...
          argsToUse = mbd.resolvedConstructorArguments;
          if (argsToUse == null) {
            argsToResolve = mbd.preparedConstructorArguments;
          }
        }
      }
      // 如果上面没有解析过,显然这里参数就是null了,argsToUse也就还为null Spring下面继续解析
      if (argsToResolve != null) {
        argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
      }
    }
    //如果缓存的构造器不存在,就说明没有bean进行过解析,需要去关联对应的bean的构造器
    if (constructorToUse == null) {
      // Need to resolve the constructor.
      // 我们的传值chosenCtors 显然不为null,所以此值为true
      boolean autowiring = (chosenCtors != null ||
          mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
      ConstructorArgumentValues resolvedValues = null;
      int minNrOfArgs;
      //若传入的构造参数不为空,那最小参数长度一塔为准 
      if (explicitArgs != null) {
        minNrOfArgs = explicitArgs.length;
      }
      else {
        // 这里相当于要解析出构造函数的参数了
        //解析对应的构造参数然后添加到ConstructorArgumentValues中
        ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
        resolvedValues = new ConstructorArgumentValues();
        minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
      }
      // Take specified constructors, if any.
      //如果传入的构造器为空,则获取bean的Class对象,然后根据bean是不是public修饰的来按照不同的方式获取所有的构造器
      // 显然,我们这里(大都都会有构造器)
      // 但是此处我们发现,即使构造器不是public的,这里也能够遭到构造器来进行实例化
      Constructor<?>[] candidates = chosenCtors;
      if (candidates == null) {
        Class<?> beanClass = mbd.getBeanClass();
        try {
          //getDeclaredConstructors返回所有的构造器(包括public和private修饰的),getConstructors返回public修饰的
          candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
        } catch (Throwable ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
              "Resolution of declared constructors on bean Class [" + beanClass.getName() +
              "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
        }
      }
      // 这个构造器排序有点意思
      //按照访问方式和数量对构造器进行排序;public>protect>private,在同为public时构造器入参多的排在前面
      // 所以排在第一位的,是public的,参数最多的构造器
      AutowireUtils.sortConstructors(candidates);
      int minTypeDiffWeight = Integer.MAX_VALUE;
      // 记录下,引起歧义的构造器们。就是记录下来,如果存在这种歧义,抛异常的时候用来告诉调用者
      Set<Constructor<?>> ambiguousConstructors = null;
      LinkedList<UnsatisfiedDependencyException> causes = null;
      // 开始遍历排序后的构造器了==========================
      for (Constructor<?> candidate : candidates) {
        // 拿到构造器参数的类型们
        Class<?>[] paramTypes = candidate.getParameterTypes();
        // constructorToUse不为null(表示已经找到了合适构造器),但是呢,连参数个数的长度都对应不上,那就直接break,后面的构造器全都不用看了
        if (constructorToUse != 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 {
            //兼容JDK6提供的@ConstructorProperties这个注解,如果它标注了参数名,那就以它的名字为准
            //@ConstructorProperties的作用=======》构造函数上的注解,显示该构造函数的参数如何与构造对象的getter方法相对应
            String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
            // 否则,就自己解析
            if (paramNames == null) {
              // 一般都是Bean工厂默认的DefaultParameterNameDiscoverer 解析出变量名
              ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
              if (pnd != null) {
                paramNames = pnd.getParameterNames(candidate);
              }
            }
            //根据获取到的参数名和已经查到的构造参数和构造参数类型来创建用户创建构造器用的构造参数数组
            //这个数组中包含了原始的参数列表和构造后的参数列表,用来对比用
            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                getUserDeclaredConstructor(candidate), autowiring);
          } catch (UnsatisfiedDependencyException ex) {
            if (this.beanFactory.logger.isTraceEnabled()) {
              this.beanFactory.logger.trace(
                  "Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
            }
            // Swallow and try next constructor.
            if (causes == null) {
              causes = new LinkedList<>();
            }
            causes.add(ex);
            continue;
          }
        } else {
          // Explicit arguments given -> arguments length must match exactly.
          if (paramTypes.length != explicitArgs.length) {
            continue;
          }
          argsHolder = new ArgumentsHolder(explicitArgs);
        }
        //lenientConstructorResolution的值ture与false有什么区别:
        //这个属性默认值是true,在大部分情况下都是使用[宽松模式],即使多个构造函数的参数数量相同、类型存在父子类、接口实现类关系也能正常创建bean。
        // false表示严格模式。与上面相反
        // typeDiffWeight:返回不同的个数的权重(权重概念?)
        int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
            argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
        // Choose this constructor if it represents the closest match.
        // 根据权重,选择一个最为合适的构造器
        if (typeDiffWeight < minTypeDiffWeight) {
          // 大都进这里来,然后是木有ambiguousConstructors 的
          constructorToUse = candidate;
          argsHolderToUse = argsHolder;
          argsToUse = argsHolder.arguments;
          minTypeDiffWeight = typeDiffWeight;
          ambiguousConstructors = null;
        }
        else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
          if (ambiguousConstructors == null) {
            ambiguousConstructors = new LinkedHashSet<>();
            ambiguousConstructors.add(constructorToUse);
          }
          ambiguousConstructors.add(candidate);
        }
      }
      // 如果此时还没发现可用的构造器,那这里就开始处理异常吧~
      if (constructorToUse == null) {
        if (causes != null) {
          UnsatisfiedDependencyException ex = causes.removeLast();
          for (Exception cause : causes) {
            this.beanFactory.onSuppressedException(cause);
          }
          throw ex;
        }
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Could not resolve matching constructor " +
            "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
      } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Ambiguous constructor matches found in bean '" + beanName + "' " +
            "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
            ambiguousConstructors);
      }
      if (explicitArgs == null) {
        argsHolderToUse.storeCache(mbd, constructorToUse);
      }
    }
    //下面步骤都是通用的,用上面得到的构造器(无论是从bean对象中获取的还是spring自己构建的)
    // 和参数来反射创建bean实例,并放到BeanWrapperImpl对象中然后返回
    try {
      // 拿到生成Bean实例化策略,默认值为CglibSubclassingInstantiationStrategy  用CGLIB生成子类的方式
      final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
      Object beanInstance;
      if (System.getSecurityManager() != null) {
        final Constructor<?> ctorToUse = constructorToUse;
        final Object[] argumentsToUse = argsToUse;
        beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
            strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
            beanFactory.getAccessControlContext());
      }
      else {
        // 主要就是调用了策略器的instantiate,对Bean进行了最终的实例化
        // 此方法为重载方法,此处因为不需要代理,所以执行的直接是SimpleInstantiationStrategy#instantiate
        // 到此处,有一个HelloServiceImpl正式创建   然后继续到doCreateBean方法去吧
        beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
      }
      bw.setBeanInstance(beanInstance);
      return bw;
    } catch (Throwable ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
          "Bean instantiation via constructor failed", ex);
    }
  }


populateBean和initializeBean

具体他俩做了什么,参考:【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的依赖注入(属性赋值)和initializeBean对Bean的初始化


总结


getBean()方法是Spring IOC容器实例化、初始化Bean的核心方法,里面的逻辑也异常的复杂。

通过阅读源码,感受最深的是:

一个优秀的框架,决不仅仅是说可以通过反射能帮助创建Bean就行了,而是像Spring这样能够考虑到各式各样的情况,有非常好的容错性、有很好的异常处理以及提示调用者报错原因。当然也有一一系列的设计原则的体现:单一职责原则、面向对象的设计原则、对扩展开放对修改关闭的原则(BeanPostProcessor是个非常好的钩子,允许我们参与进Bean的声明周期中来)

阅读优秀的源码,能够在我们更深的理解到:优秀只所以优秀,是因为真的很优秀!!!


相关文章
|
30天前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
49 0
|
14天前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
14天前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
91 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
1天前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
1天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
30天前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
48 0
|
1月前
|
Java Spring
|
1月前
|
前端开发 Java 开发者
|
3月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
43 2
|
3月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
45 0