【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的属性赋值和initializeBean对Bean的初始化(上)

简介: 【小家Spring】AbstractAutowireCapableBeanFactory#populateBean实现Bean的属性赋值和initializeBean对Bean的初始化(上)

前言


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

源码分析的时候,留下两个重要的步骤还没有说,一个是属性赋值的populateBean()(依赖注入),还有一个就是赋值后对Bean的一些初始化操作:initializeBean()


Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

AbstractAutowireCapableBeanFactory#populateBean实现依赖注入


在完成Bean实例化后,Spring容器会给这个Bean注入相关的依赖Bean,在源码中,这一步通过类AbstractAutowireCapableBeanFactory中的populateBean方法完成。


  protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 对实例做的一个判空校验
    if (bw == null) {
      if (mbd.hasPropertyValues()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      } else {
        // Skip property population phase for null instance.
        return;
      }
    }
    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set. This can be used, for example,
    // to support styles of field injection.
    boolean continueWithPropertyPopulation = true;
    //给InstantiationAwareBeanPostProcessors最后一次机会在属性注入前修改Bean的属性值
    //具体通过调用postProcessAfterInstantiation方法,如果调用返回false,表示不必继续进行依赖注入,直接返回
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
          //postProcessAfterInstantiation 这个方法返回true,后面的处理器才会继续执行,单反返回false,后面的就不会再执行了
          //并且continueWithPropertyPopulation 打上标记表示false,也就是说后面的属性复制就不会再执行了
          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
          }
        }
      }
    }
    // 处理器若告知说不用继续赋值了,那就以处理器的结果为准即可
    if (!continueWithPropertyPopulation) {
      return;
    }
    //pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
    //本例中,我们的helloServiceImpl的Bean定义里,pvs为null
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    //根据Bean配置的依赖注入方式完成注入,默认是0,即不走以下逻辑,所有的依赖注入都需要在xml(或者@Bean中)文件中有显式的配置
    //如果设置了相关的依赖装配方式,会遍历Bean中的属性,根据类型或名称来完成相应注入,无需额外配置
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      // 深拷贝当前已有的配置
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      // 根据名称进行注入(见下)
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      // 根据类型进行注入(见下)
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
      }
      //结合注入后的配置,覆盖当前配置
      pvs = newPvs;
    }
    // 显然hasInstAwareBpps=true,
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    //是否进行依赖检查  默认值就是None  所以此处返回false,表示不需要依赖检查(关于依赖检查的4种模式,建议使用@Required来显示控制)
    //@Required注解作用于Beansetter方法上,用于检查一个Bean的属性的值在配置期间是否被赋予或设置(populated)
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (hasInstAwareBpps || needsDepCheck) {
      if (pvs == null) {
        pvs = mbd.getPropertyValues();
      }
      // 过滤出所有需要进行依赖检查的属性编辑器
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      // 在这个节点上:调用了InstantiationAwareBeanPostProcessor#postProcessPropertyValues方法,
      // 若返回null,整个populateBean方法就结束了=============
      if (hasInstAwareBpps) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 关于postProcessPropertyValues的实现,有几个处理器是非常关键的:
            // 比如AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等等,且看下面的分解
            pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            // 若返回null,Spring表示你已经属性值都设置好了,那他也不再管了
            if (pvs == null) {
              return;
            }
          }
        }
      }
      // 显然,现在大多数情况下,都不会在check这个了
      if (needsDepCheck) {
        checkDependencies(beanName, mbd, filteredPds, pvs);
      }
    }
    // 将pvs上所有的属性填充到BeanWrapper对应的Bean实例中
    // 注意:这一步完成结束后为止。我们的HelloServiceImpl这个Bean依赖的parent,还只是RuntimeBeanReference类型,还并不是真实的Parent这个Bean
    //在Spring的解析段,其它容器中是没有依赖的Bean的实例的,因此这个被依赖的Bean需要表示成RuntimeBeanReferenc对象,并将它放到BeanDefinition的MutablePropertyValues中。
    if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
    }
  }


先看看autowireByName和autowireByType这两步是怎么实现的:


  protected void autowireByName(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    //根据bw的PropertyDescriptors,遍历出所有可写的(即set方法存在),存在于BeanDefinition里的PropertyValues,且不是简单属性的属性名
    //简单属性的判定参照下面方法,主要涵盖基本类型及其包装类,Number,Date等=============
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
      // 显然,只有容器里存在的,才能根据这个名称注册进去。
      //注意,这里存在,有点意思:含有Bean,或者Bean定义等等都算
      /** @Override
      public boolean containsBean(String name) {
        String beanName = transformedBeanName(name);
        // 首先工厂里必须有单例Bean,或者bean定义
        // 然后还必须不是BeanFactory(不是&打头),或者是FactoryBean  就算是包含这个Bean的
        if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
          return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
        }
        // Not found -> check parent.  看看父容器里有木有
        BeanFactory parentBeanFactory = getParentBeanFactory();
        return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
      } */
      // 再说明一下containsLocalBean这个方法,和containsBean的区别在于它只在自己的容器里找,不去父容器里找,其余的一样
      if (containsBean(propertyName)) {
        // 注意:此处找到依赖了,调用了getBean(),所以即使你现在仅仅只是Bean定义,那么会被创建实例对象
        Object bean = getBean(propertyName);
        pvs.add(propertyName, bean);
        // 注册依赖关系
        // 此处需要知道的是:Spring中使用dependentBeanMap和dependenciesForBeanMap来管理这些Bean的依赖关系:
        //Map<String, Set<String>> dependentBeanMap:存放着当前Bean被引用的Bean的集合
        //Map<String, Set<String>> dependenciesForBeanMap:存放的则是当前Bean所依赖的Bean的集合
        //依赖注入的具体实现是在BeanWrapperImpl类中的setPropertyValue方法里=======================
        registerDependentBean(propertyName, beanName);
        if (logger.isDebugEnabled()) {
          logger.debug("Added autowiring by name from bean name '" + beanName +
              "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
        }
      } else {
        if (logger.isTraceEnabled()) {
          logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
              "' by name: no matching bean found");
        }
      }
    }
  }
  protected void autowireByType(
      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    // 类型转换器,如果没有指定,就用BeanWrapper这个转换器
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
      converter = bw;
    }
    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
      try {
        PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
        // Don't try autowiring by type for type Object: never makes sense,
        // even if it technically is a unsatisfied, non-simple property.
        //如果是Object类型不进行装配==============
        if (Object.class != pd.getPropertyType()) {
          // 获取相关的写方法参数
          MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
          // Do not allow eager init for type matching in case of a prioritized post-processor.
          // 看看实例是否实现了PriorityOrdered接口,若没有实现  就稍后点加载吧-----
          boolean eager = !PriorityOrdered.class.isInstance(bw.getWrappedInstance());
          DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
          // 这里会根据传入desc里的入参类型,作为依赖装配的类型
          // 再根据这个类型在BeanFacoty中查找所有类或其父类相同的BeanName
          // 最后根据BeanName获取或初始化相应的类,然后将所有满足条件的BeanName填充到autowiredBeanNames中。
          Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
          if (autowiredArgument != null) {
            pvs.add(propertyName, autowiredArgument);
          }
          // 需要注入的依赖都拿到后,就开始注册这些依赖吧
          for (String autowiredBeanName : autowiredBeanNames) {
            // 一样的 这里注册这些依赖
            registerDependentBean(autowiredBeanName, beanName);
          }
          autowiredBeanNames.clear();
        }
      } catch (BeansException ex) {
        throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
      }
    }
  }


相关文章
|
2月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
53 0
|
19天前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
19天前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
116 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
7天前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
7天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
2月前
|
Java Spring
|
2月前
|
前端开发 Java 开发者
|
4月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
45 2
|
4月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
45 0
|
3月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
87 11
下一篇
无影云桌面