Spring 中 populateBean 详解

1,369 阅读6分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

1.前言

populateBean :使用来自bean definition 的属性值在给定的BeanWrapper中填充bean实例。

这个方法在spring 容器初始化调用的位置: org.springframework.context.support.AbstractApplicationContext#refresh --》 org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization --》 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons --》 org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) --》 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[]) --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean --》 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

2.populateBean 源码

鉴于这个方法比较长,所以这里我们还是一块一块的讲

2.1 跳过null bean 的属性注入

图片.png

  • 首先它会判断这个 BeanWrapper(bw)是不是null,
    • mbd.hasPropertyValues():如果有给该bean定义的属性值,则返回
    • 当 bw 是null时,应该不能有为该bean 定义的属性值,有的话抛出异常
    • 没有的话,则跳过null 实例的属性解析

2.2 给 InstantiationAwareBeanPostProcessors 最后一次机会在属性注入前修改Bean的属性值

图片.png

  • continueWithPropertyPopulation:是否需要继续给属性注入值
  • mbd.isSynthetic(): 返回bean definition 是否是合成的,(合成:即不是应用程序本身定义的)
  • hasInstantiationAwareBeanPostProcessors():返回该工厂是否持有实例化的WareBeanPostProcessor,该实例化将在关闭时应用于单例bean。 图片.png
  • 当这个bean不是合成的,且它持有实例化的WareBeanPostProcessor ,则获取所有的BeanPostProcessor,判断当它是InstantiationAwareBeanPostProcessors 类型时,通过调用postProcessAfterInstantiation方法,可以在属性注入前,最后一次修改bean的值,如果调用返回false,表示不必继续进行依赖注入,直接返回
  • postProcessAfterInstantiation :如果我们需要在这一步修改,则可以重写这个方法,目前默认方法体,直接返回true

2.3 选择合适的注入模式

图片.png

  • 判断当前bean 有无定义的属性值,如果有就返回当前bean 所有的属性值,否则返回null

    • mbd.getPropertyValues(): 图片.png
    • 这里我们可以看到pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,主要作用是:提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
  • mbd.getResolvedAutowireMode():获取注入方式。 图片.png

    • AUTOWIRE_NO = 0(默认):常量,指示没有外部定义的自动注入
    • AUTOWIRE_BY_NAME = 1:常量,指示按名称自动装配bean属性
    • AUTOWIRE_BY_TYPE = 2:常量,指示按类型自动装配bean属性
    • AUTOWIRE_CONSTRUCTOR = 3:常量,指示自动关联最贪婪的构造函数
    • AUTOWIRE_AUTODETECT = 4:常数,表示通过bean类的自省来确定适当的自动装配策略
  • 所以这个方法,先判断它需不需要自省,不需要直接返回它本身,需要的话根据构造函数的参数数量来判断,参数数量为0 返回 AUTOWIRE_BY_TYPE,否则 返回 AUTOWIRE_CONSTRUCTOR

  • 通过前面获取的 resolvedAutowired,来选择合适的注入方式

  • autowireByName :通过名称自动装配,详解见 2.3.1

  • autowireByType : 通过类型自动装配,详解见 2.3.2

  • 把注入后的 newPvs 重新赋给 pvs

1. autowireByName(beanName, mbd, bw, newPvs)

图片.png

  • propertyNames :首先获取所有需要进行依赖注入的属性名称,然后保存起来。详解见 2.3.3
  • 遍历 propertyNames ,判断容器中是否含有该 属性的bean,注意:这里含有bean 或 bean 的定义都算。详解见2.3.4
  • 如果包含的话,先从容器中获取到这个bean,则把它 name -> bean 加入到 pvs 中去
  • 最后把它注册到当前bean 的 dependentBeanMap(保存当前bean 依赖的bean 的名称集合)中去

2. autowireByType(beanName, mbd, bw, newPvs);

图片.png

  • 获取类型转换器,如果没有,就直接使用 bw ,BeanWrapper详解
  • autowiredBeanNames : 保存以来的bean 的名称的 Set 集合。
  • propertyNames :首先获取所有需要进行依赖注入的属性名称,然后保存起来。详解见 2.3.3
  • 遍历 propertyNames ,
  • getPropertyDescriptor(propertyName):获取被包装对象的特定属性的属性描述符
  • 如果属性是 Object 类型的 则不进行 装配
  • 获取属性的写方法相关参数
  • 判断它有没有实现,PriorityOrdered.class 接口
  • 封装一个 依赖描述的对象,AutowireByTypeDependencyDescriptor(记录了依赖对象的基本信息,源码挺简单的,就是设置一些属性,大家可以自己看看)
  • resolveDependency(desc, beanName, autowiredBeanNames, converter):这里会根据传入desc里的入参类型,作为依赖装配的类型,再根据这个类型在BeanFacoty中查找所有类或其父类相同的BeanName,最后根据BeanName获取或初始化相应的类,然后将所有满足条件的BeanName填充到 autowiredBeanNames 中。这个方法后续有时间的话,会详解
  • 当 autowired 不为null 的时候,把它添加到 pvs 中去
  • 遍历 autowiredBeanNames 最后把它注册到当前bean 的 dependentBeanMap(保存当前bean 依赖的bean 的名称集合)中去

3. unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw)

图片.png

  • 属性的写方法不为null && 该属性需要进行依赖检查的 && bean Definition 中没有包含的 && 不是简单属性,或数据元素是简单属性的数组,符合上面条件的元素,把他们的属性名返回
  • 简单属性: 图片.png

4. containsBean(String name)

图片.png

  • 先判断当前容器中有无,该name 处理后的beanName 的 bean 或者 beanDefinition 信息,如果有则继续判断当它不是BeanFactory (即 name不为null 且 name 不以 '&' 开头)或者它是一个 FactoryBean 则返回true,算包含。
  • 当本容器不包含的时候,会尝试获取它的 父容器,接着判断,直至父容器为 null

2.4 属性值的填充和依赖检查

图片.png

  • hasInstAwareBpps : 是否持有实例化 InstantiationAwareBeanPostProcessor 的bean
  • needsDepCheck : 是否需要类型检查(setter 方法上使用@Required ,用来检查指定属性,是否被赋值)
  • filteredPds : 保存属性描述符的数组
  • 当 hasInstAwareBpps 为 true
    • 遍历当前bean 所有的 BeanPostProcessor ,当它是 InstantiationAwareBeanPostProcessor 类型时,执行 postProcessProperties 这个方法。
    • postProcessProperties:在工厂将给定的属性值应用到给定的bean之前对它们进行后处理,不需要任何属性描述符。如:@Resource , @Autowired, @Value ,@Inject 等注解 进行值注入。AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor 等均实现了。 图片.png
    • 当pvsToUse == null 的时候,调用 filterPropertyDescriptorsForDependencyCheck,对bw 的属性进行过滤注册(cglib 代理的属性 || 指定需要过滤的类型 || 需要忽略的接口类型),详解见 2.4.1
    • 执行当前 InstantiationAwareBeanPostProcessor 的 postProcessPropertyValues (这里大多实现类这个方法已废弃,应该是对以前低版本的兼容)
    • postProcessPropertyValues:作用和 postProcessProperties 差不多,已废弃
  • 当需要依赖检查时进入,
    • 当 filteredPds 仍为 null ,调用 filterPropertyDescriptorsForDependencyCheck 对bw 的属性进行过滤注册,详解见 2.4.1
    • 进行依赖检查,详解见 2.4.4

1.filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw, boolean cache)

图片.png

  • filteredPropertyDescriptorsCache :已筛选PropertyDescriptor的缓存:bean类到PropertyDescriptor数组
  • 先通过 bean 类从 filteredPropertyDescriptorsCache 中取出 PropertyDescriptor 数组
  • 当 filtered == null 时,进入
    • filterPropertyDescriptorsForDependencyCheck(bw):从给定的BeanWrapper中提取一组经过过滤的propertydescriptor,不包括被忽略的依赖类型或被忽略的属性,详解见 2.4.2
    • cache == true时,且 filteredPropertyDescriptorsCache 中取出的 filtered不为null,则把过滤后的属性数组,再放到 filteredPropertyDescriptorsCache 中去
  • 返回 filtered

2. filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw)

图片.png

  • 从bw 中取出所有的 PropertyDescriptor,然后调用 isExcludedFromDependencyCheck(2.4.3 详解) 这个方法 进行过滤

3. isExcludedFromDependencyCheck(PropertyDescriptor pd)

图片.png 这里其实就是过滤 cglib 代理的属性 || 指定需要过滤的类型 || 需要忽略的接口类型 图片.png 图片.png 图片.png

4. checkDependencies(beanName, mbd, filteredPds, pvs);

图片.png

  • 获取mbd 的依赖检查类型
    • DEPENDENCY_CHECK_NONE = 0 :常量,表示根本没有依赖项检查
    • DEPENDENCY_CHECK_OBJECTS = 1:常量,表示对象引用的依赖性检查。
    • DEPENDENCY_CHECK_SIMPLE = 2: 常量,指示对“简单”属性进行依赖性检查。
    • DEPENDENCY_CHECK_ALL = 3: 常量,指示对所有属性进行依赖性检查
  • 当它写方法不为null && (pvs == null || pvs 不包含当前 属性名)
    • isSimple : 记录当前这个这个属性是不是简单属性
    • 当 unsatisfied ==true 时,抛出异常

2.5 最终处理

图片.png applyPropertyValues :把当前属性填充给这个bean,因为这个方法比较长,今天就先到这 ,下次我在详细讲讲。