【小家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);
      }
    }
  }


相关文章
|
1月前
|
XML 安全 Java
|
27天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
27天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
1月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
66 6
|
1月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
116 3
|
2月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
101 4
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
1月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
42 1
|
1天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
56 17
Spring Boot 两种部署到服务器的方式
|
1天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
29 17
springboot自动配置原理
|
6天前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
43 11