AI智能
改变未来

死磕Spring之IoC篇 – Bean 的属性填充阶段

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读

Spring 版本:5.1.14.RELEASE

开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章

该系列其他文章请查看:《死磕 Spring 之 IoC 篇 – 文章导读》

Bean 的属性填充阶段

当我们显示或者隐式地调用

AbstractBeanFactory

getBean(...)

方法时,会触发 Bean 的加载,在《开启 Bean 的加载》文章中分析了整个加载过程。

对于不同作用域的 Bean,底层都会调用

AbstractAutowireCapableBeanFactory

createBean(...)

方法进行创建,在《Bean 的创建过程》文章中分析了整个创建过程。创建 Bean 的过程中,在获取到的一个实例对象后,里面的相关属性也许是空的,那么接下来要做的就是将需要填充的属性进行依赖注入,然后再进行后续的初始化工作。整个的属性填充过程非常复杂,因为配置的属性值可能是一个表达式,需要解析,类型也可能不对,需要进行类型转换,还可能是一个对象,需要找到对应的 Bean 然后注入(依赖注入),存在有各种处理,本文将会分析创建 Bean 过程中的属性填充阶段。

回顾

先来回顾一下创建 Bean 过程中属性填充阶段对应的代码:

// AbstractAutowireCapableBeanFactory#doCreateBean(...) 方法// Initialize the bean instance.// 开始初始化 `bean`Object exposedObject = bean;try {// <4> 对 `bean` 进行属性填充,注入对应的属性值populateBean(beanName, mbd, instanceWrapper);// <5> 初始化这个 `exposedObject`,调用其初始化方法exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}

在创建好实例对象后,这个对象的属性还没有赋值,所以将这个实例对象的相关属性进行赋值,也就是上面的第

<4>

开启 Bean 的属性填充

populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)

方法,属性填充,如下:

// AbstractAutowireCapableBeanFactory.javaprotected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// <1> 如果实例对象为空,则进行下面的判断if (bw == null) {// <1.1> 这个 Bean 有属性,则抛出异常if (mbd.hasPropertyValues()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}// <1.2> 否则,不用属性填充,直接 `return`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.// <2> 实例化阶段的后置处理,如果满足这两个条件if (!mbd.isSynthetic() // RootBeanDefinition 不是用户定义的(由 Spring 解析出来的)&& hasInstantiationAwareBeanPostProcessors()) { // 是否有 InstantiationAwareBeanPostProcessor 处理器// <2.1> 遍历所有的 BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {// 如果为 InstantiationAwareBeanPostProcessor 类型if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;// <2.2> 对实例化对象进行后置处理// 注意如果返回 false,直接 `return`,不会调用后面的 InstantiationAwareBeanPostProcessor 处理器,也不会进行接下来的属性填充if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;}}}}// <3> 获取 `pvs`,承载当前对象的属性值PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);// <4> 获取这个 Bean 的注入模式,默认为 **AUTOWIRE_NO**,例如可以通过 `@Bean` 注解的 `autowire` 属性配置注入模式int resolvedAutowireMode = mbd.getResolvedAutowireMode();// <4.1> 如果注入模式为 **AUTOWIRE_BY_NAME** 或者 **AUTOWIRE_BY_TYPE**,则通过下面的方式获取属性值if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {// <4.2> 将 `pvs` 封装成 MutablePropertyValues 对象 `newPvs`(允许对属性进行相关操作)MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.// <4.3> **AUTOWIRE_BY_NAME** 模式,通过名称获取相关属性值,保存在 `newPvs` 中if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.// <4.4> **AUTOWIRE_BY_TYPE** 模式,通过类型获取相关属性值,保存在 `newPvs` 中if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}// <4.5> 将 `newPvs` 复制给 `pvs`pvs = newPvs;}// 是否有 InstantiationAwareBeanPostProcessor 处理器boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();// 是否需要进行依赖检查,默认为 trueboolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;// <5> 通过 InstantiationAwareBeanPostProcessor 处理器(如果有)对 `pvs` 进行处理if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}// <5.1> 遍历所有的 BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {// 如果为 InstantiationAwareBeanPostProcessor 类型if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;/*** Spring 内部的 InstantiationAwareBeanPostProcessor 处理器:* {@link AutowiredAnnotationBeanPostProcessor#postProcessProperties} 会解析 @Autowired 和 @Value 注解标注的属性,获取对应属性值;* {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties} 会解析 @Resource 注解标注的属性,获取对应的属性值*/// <5.2> 调用处理器的 `postProcessProperties(...)` 方法,对 `pvs` 进行后置处理PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);// <5.3> 如果上一步的处理结果为空,可能是新版本导致的(Spring 5.1 之前没有上面这个方法),则需要兼容老版本if (pvsToUse == null) {// <5.3.1> 找到这个 Bean 的所有 `java.beans.PropertyDescriptor` 属性描述器(包含这个属性的所有信息)if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}// <5.3.2> 调用处理器的 `postProcessPropertyValues(...)` 方法,对 `pvs` 进行后置处理pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);// <5.3.3> 如果处理后的 PropertyValues 对象为空,直接 `return`,则不会调用后面的 InstantiationAwareBeanPostProcessor 处理器,也不会进行接下来的属性填充if (pvsToUse == null) {return;}}// <5.4> 将处理后的 `pvsToUse` 复制给 `pvs`pvs = pvsToUse;}}}// <6> 依赖检查if (needsDepCheck) {// <6.1> 找到这个 Bean 的所有 `java.beans.PropertyDescriptor` 属性描述器(包含这个属性的所有信息)if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}// <6.2> 依赖检查,如果没有找到对应的属性值,则根据检查策略进行抛出异常(默认不会)checkDependencies(beanName, mbd, filteredPds, pvs);}// <7> 如果 `pvs` 不为空,则将里面的属性值设置到当前 Bean 对应的属性中(依赖注入)// 前面找到的属性值并没有设置到 Bean 中,且属性值可能是一个表达式,类型也可能也不对,需要先进行处理和类型转换,然后再设置到该实例对象中if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}}

过程大致如下:

  1. 如果实例对象为

    null

    ,则进行下面的判断

    这个 Bean 有属性,则抛出异常

  2. 否则,不用属性填充,直接
    return
  • 实例化阶段的后置处理,如果满足这两个条件:RootBeanDefinition 不是用户定义的(由 Spring 解析出来的)、是否有 InstantiationAwareBeanPostProcessor 处理器

      遍历所有的 BeanPostProcessor

    1. 如果为 InstantiationAwareBeanPostProcessor 类型,则对实例化对象进行后置处理

      注意,如果返回 false,直接

      return

      ,不会调用后面的 InstantiationAwareBeanPostProcessor 处理器,也不会进行接下来的属性填充

  • 获取

    pvs

    ,承载当前对象的属性值

  • 获取这个 Bean 的注入模式,默认为 AUTOWIRE_NO,例如可以通过

    @Bean

    注解的

    autowire

    属性配置注入模式

      如果注入模式为 AUTOWIRE_BY_NAME 或者 AUTOWIRE_BY_TYPE,则通过下面的方式获取属性值
    1. pvs

      封装成 MutablePropertyValues 对象

      newPvs

      (允许对属性进行相关操作)

    2. AUTOWIRE_BY_NAME 模式,通过名称获取相关属性值,保存在
      newPvs

      中,调用

      autowireByName(...)

      方法

    3. AUTOWIRE_BY_TYPE 模式,通过类型获取相关属性值,保存在
      newPvs

      中,调用

      autowireByType(...)

      方法

    4. newPvs

      复制给

      pvs
  • 通过 InstantiationAwareBeanPostProcessor 处理器(如果有)对

    pvs

    进行处理

      遍历所有的 BeanPostProcessor
    1. 如果为 InstantiationAwareBeanPostProcessor 类型,则调用其
      postProcessProperties(...)

      方法,对

      pvs

      进行后置处理

    2. 如果上一步的处理结果为空,可能是新版本导致的(Spring 5.1 之前没有上面这个方法),则需要兼容老版本尝试找到这个 Bean 的所有
      java.beans.PropertyDescriptor

      属性描述器(包含这个属性的所有信息)

    3. 调用处理器的
      postProcessPropertyValues(...)

      方法,对

      pvs

      进行后置处理

    4. 如果处理后的 PropertyValues 对象为空,直接
      return

      ,则不会调用后面的处理器,也不会进行接下来的属性填充

  • 将处理后的
    pvsToUse

    复制给

    pvs
  • 依赖检查

      找到这个 Bean 的所有

      java.beans.PropertyDescriptor

      属性描述器(包含这个属性的所有信息)

    1. 进行依赖检查,如果没有找到对应的属性值,则根据检查策略进行抛出异常(默认不会)
  • 如果

    pvs

    不为空,则将里面的属性值设置到当前 Bean 对应的属性中(依赖注入),调用

    applyPropertyValues(...)

    方法

    前面找到的属性值并没有设置到 Bean 中,且属性值可能是一个表达式,类型也可能也不对,需要先进行处理和类型转换,然后再设置到该实例对象中

  • 整个的属性填充过程非常的复杂,接下来进行概括:

    • 允许你对实例化对象进行后置处理,处理结果为
      false

      表示不需要进行接下来的属性填充过程

    • 根据注入模式,找到没有配置属性值的对象属性,然后找到对应的 Bean,默认注入模式为不注入
    • 允许你对属性值进行后置处理,例如
      @Autowired

      @Value

      等注解标注的属性会通过这里找到对应的属性值(或对象)

    • 上述过程仅找到了属性值,还没设置到当前实例对象中,所以最后一步才是真正的属性填充

    上面有两种注入模式:AUTOWIRE_BY_NAMEAUTOWIRE_BY_TYPE,默认为 AUTOWIRE_NO,接下来先来看看这两种注入模式的实现

    通过名称获取属性值

    autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs)

    方法,通过名称获取相关属性值,如下:

    // AbstractAutowireCapableBeanFactory.javaprotected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {// <1> 获取当前 Bean 中不满意的非简单类型的属性名称,也就是没有定义属性值的"对象"属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);// <2> 遍历这些对象属性的名称for (String propertyName : propertyNames) {// <3> 如果当前容器存在对应的 Bean(通过名称判断)if (containsBean(propertyName)) {// <3.1> 根据属性名称获取对应的 `bean` 对象(依赖查找)Object bean = getBean(propertyName);// <3.2> 将 `bean` 添加至 `pvs`pvs.add(propertyName, bean);// <3.3> 将两个 Bean 之间的依赖关系保存起来registerDependentBean(propertyName, beanName);if (logger.isTraceEnabled()) {logger.trace("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");}}}}

    过程并不复杂,大致如下:

    1. 获取当前 Bean 中不满意的非简单类型的属性名称,也就是没有定义属性值的**"对象"**属性,如下:

      // AbstractAutowireCapableBeanFactory.javaprotected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {Set<String> result = new TreeSet<>();// 获取已设置的属性值PropertyValues pvs = mbd.getPropertyValues();// 找到这个 Bean 的所有 PropertyDescriptor 属性描述器(包含这个属性的所有信息)PropertyDescriptor[] pds = bw.getPropertyDescriptors();// 遍历所有属性for (PropertyDescriptor pd : pds) {if (pd.getWriteMethod() != null // 有可写方法&& !isExcludedFromDependencyCheck(pd) // 不忽略&& !pvs.contains(pd.getName()) // 没有对应的属性值&& !BeanUtils.isSimpleProperty(pd.getPropertyType())) // 不是简单类型(例如一个实体类){result.add(pd.getName());}}// 返回这些不满意的非简单类型的属性return StringUtils.toStringArray(result);}
    2. 遍历这些对象属性的名称

    3. 如果当前容器存在对应的 Bean(通过名称判断)

      根据属性名称获取对应的

      bean

      对象(依赖查找

    4. bean

      添加至

      pvs
    5. 将两个 Bean 之间的依赖关系保存起来

    直接根据**"对象"**名称通过

    getBean(String beanName)

    获取到对应的对象(依赖查找

    通过类型获取属性值

    autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs)

    方法,通过类型获取相关属性值,如下:

    // AbstractAutowireCapableBeanFactory.javaprotected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {// <1> 获取 TypeConverter 类型转换器,用于取代默认的 PropertyEditor 类型转换器// 例如 Spring 3.0 之后的 ConversionServiceTypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}Set<String> autowiredBeanNames = new LinkedHashSet<>(4);// <2> 获取当前 Bean 中不满意的非简单类型的属性名称,也就是没有定义属性值的"对象"属性String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);// <3> 遍历这些对象属性的名称for (String propertyName : propertyNames) {try {// <3> 获取这个属性的 `java.beans.PropertyDescriptor` 属性描述器(包含这个属性的所有信息)PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);// <4> 如果不是 Object 类型(对 Object 类类型的 Bean 进行自动装配毫无意义),则尝试找到对应的对象if (Object.class != pd.getPropertyType()) {// <5> 找到这个属性的写方法MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.// 是否可以提前初始化boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);// <6> 创建对应的依赖注入描述对象DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);// <7> 依赖注入,找到该属性对应的对象Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);// <8> 如果找到属性对象,则将该其添加至 `pvs`if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument);}// <9> 将注入的属性对象和当前 Bean 之前的关系保存起来// 因为该属性可能是一个集合,找到了多个对象,所以这里是一个数组for (String autowiredBeanName : autowiredBeanNames) {// 将 `autowiredBeanName` 与 `beanName` 的依赖关系保存registerDependentBean(autowiredBeanName, beanName);if (logger.isTraceEnabled()) {logger.trace("Autowiring by type from bean name \'" + beanName + "\' via property \'" +propertyName + "\' to bean named \'" + autowiredBeanName + "\'");}}// 清空 `autowiredBeanName` 数组autowiredBeanNames.clear();}} catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);}}}

    过程大致如下:

    1. 获取 TypeConverter 类型转换器,用于取代默认的 PropertyEditor 类型转换器
    2. 获取当前 Bean 中不满意的非简单类型的属性名称,也就是没有定义属性值的**"对象"属性,和通过名称注入**的过程一样
    3. 遍历这些**"对象"**属性的名称,获取这个属性的
      java.beans.PropertyDescriptor

      属性描述器(包含这个属性的所有信息)

    4. 如果不是 Object 类型(对 Object 类类型的 Bean 进行自动装配毫无意义),则尝试找到对应的对象
    5. 找到这个属性的写方法
    6. 创建对应的 DependencyDescriptor 依赖注入描述对象,默认 required 为 false,表示找不到也没关系
    7. 依赖注入,找到该属性对应的对象,调用
      resolveDependency(...)

      方法

    8. 如果找到属性对象,则将该其添加至
      pvs
    9. 将注入的属性对象和当前 Bean 之前的关系保存起来

    根据**"对象"名称通过

    resolveDependency(...)

    获取到对应的对象,该方法就是依赖注入**的底层实现,整个过程也非常复杂,所以将这部分内容放在下一篇《@Autowired 等注解的实现原理》文章中

    属性值的后置处理

    调用

    InstantiationAwareBeanPostProcessor#postProcessProperties

    方法,对前面属性值进行处理

    在前面的AUTOWIRE_BY_NAMEAUTOWIRE_BY_TYPE两种注入模式中,找到的都是普通对象的属性值,例如 @Autowired、@Value 和 @Resource 注解并没有被解析,且默认的注入模式还是AUTOWIRE_NO,那这些注解是如何被解析的呢?Spring 内部有下面两个 InstantiationAwareBeanPostProcessor 处理器:

    • AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解标注的属性,获取对应属性值
    • CommonAnnotationBeanPostProcessor,会解析 @Resource 注解标注的属性,获取对应的属性值

    这里先提一下,具体的实现过程在下一篇《@Autowired 等注解的实现原理》文章中进行分析

    属性填充

    applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)

    方法,属性填充

    如果获取到的

    pvs

    属性值对象不为空,则将里面的属性值设置到当前 Bean 对应的属性中(依赖注入),我们知道前面找到的属性值并没有设置到 Bean 中,且属性值可能是一个表达式,类型也可能也不对,需要先进行处理和类型转换,然后再设置到该实例对象中,方法如下:

    // AbstractAutowireCapableBeanFactory.javaprotected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {// <1> 没有相关属性值,则直接 `return` 返回if (pvs.isEmpty()) {return;}if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());}// ------------------------开始属性值的转换与填充------------------------MutablePropertyValues mpvs = null;// 定义一个 `original` 集合,承载属性值(未进行转换)List<PropertyValue> original;// <2> 如果 `pvs` 是 MutablePropertyValues 类型,则可能已经处理过了if (pvs instanceof MutablePropertyValues) {mpvs = (MutablePropertyValues) pvs;if (mpvs.isConverted()) {// Shortcut: use the pre-converted values as-is.try {// <2.1> 属性值已经转换了,则将这些属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!bw.setPropertyValues(mpvs);return;}catch (BeansException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}// <2.2> 没有转换过,则获取所有的属性值集合original = mpvs.getPropertyValueList();}else {// <2.2> 获取所有的属性值集合original = Arrays.asList(pvs.getPropertyValues());}// 获取 TypeConverter 类型转换器,用于取代默认的 PropertyEditor 类型转换器// 例如 Spring 3.0 之后的 ConversionServiceTypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}// 获取对应的解析器BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);// Create a deep copy, resolving any references for values.// <3> 定义一个 `deepCopy` 集合,保存转换后的属性值List<PropertyValue> deepCopy = new ArrayList<>(original.size());boolean resolveNecessary = false;// <4> 遍历所有的属性值,进行转换(如果有必要)for (PropertyValue pv : original) {// <4.1> 已经转换过,则直接添加到 `deepCopy` 中if (pv.isConverted()) {deepCopy.add(pv);}// <4.2> 否则,开始进行转换else {String propertyName = pv.getName();// 转换之前的属性值Object originalValue = pv.getValue();// <4.2.1> 表达式的处理(如果有必要的话),例如你在 XML 配置的属性值为 `${systenm.user}`,则会解析出对应的值Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);// 转换之后的属性值Object convertedValue = resolvedValue;// 该属性是否可以转换boolean convertible = bw.isWritableProperty(propertyName) && // 属性可写!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); // 不包含 `.` 和 `[`if (convertible) {// <4.2.2> 使用类型转换器转换属性值(如果有必要的话)convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);}// Possibly store converted value in merged bean definition,// in order to avoid re-conversion for every created bean instance.if (resolvedValue == originalValue) { // 属性值没有转换过if (convertible) {// <4.2.3> 设置转换后的值,避免上面的各种判断pv.setConvertedValue(convertedValue);}// <4.2.4> 添加到 `deepCopy` 中deepCopy.add(pv);}// 属否则属性值进行了转换else if (convertible // 可转换的&& originalValue instanceof TypedStringValue // 属性原始值是字符串类型&& !((TypedStringValue) originalValue).isDynamic() // 属性的原始类型值不是动态生成的字符串&& !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) // 属性的原始值不是集合或者数组类型{// <4.2.3> 设置转换后的值,避免上面的各种判断pv.setConvertedValue(convertedValue);// <4.2.4> 添加到 `deepCopy` 中deepCopy.add(pv);}// 否则else {// 这个属性每次都要处理,不能缓存resolveNecessary = true;// <4.2.4> 添加到 `deepCopy` 中deepCopy.add(new PropertyValue(pv, convertedValue));}}}// <5> 如果属性值不为空,且不需要每次都处理,则设置为已转换if (mpvs != null && !resolveNecessary) {mpvs.setConverted();}// Set our (possibly massaged) deep copy.try {// <6> 将属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!bw.setPropertyValues(new MutablePropertyValues(deepCopy));}catch (BeansException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}}

    过程大致如下:

    1. 没有相关属性值,则直接
      return

      返回

    开始属性值的转换与填充,先定义一个

    original

    集合,承载属性值(未进行转换)

    1. 如果

      pvs

      是 MutablePropertyValues 类型,则可能已经处理过了,否则,获取所有的属性值集合,放入

      original

      集合中

      [ol]

      属性值已经转换了,则将这些属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!

      调用

      BeanWrapperImpl#setPropertyValues(PropertyValues)

      方法

    2. 没有转换过,则获取所有的属性值集合,放入

      original

      集合中

  • 定义一个

    deepCopy

    集合,保存转换后的属性值

  • 遍历所有的属性值,进行转换(如果有必要)

      已经转换过,则直接添加到

      deepCopy

    1. 否则,开始进行转换表达式的处理(如果有必要的话),例如你在 XML 配置的属性值为
      ${systenm.user}

      ,则会解析出对应的值

    2. 使用类型转换器转换属性值(如果有必要的话)
    3. 设置转换后的值,避免上面的各种判断
    4. 添加到
      deepCopy

    [/ol]

  • 如果属性值不为空,且不需要每次都处理,则设置为已转换

  • 将属性值设置到当前 Bean 中(反射机制),依赖注入的最终实现!!!

    调用

    BeanWrapperImpl#setPropertyValues(PropertyValues)

    方法

  • 整个属性注入过程非常复杂,上面仅列出了关键步骤,可以看到最终会调用

    BeanWrapperImpl#setPropertyValues(PropertyValues)

    方法将属性值设置到 Bean 中

    在 Bean 的实例化阶段获取到的就是一个 BeanWrapperImpl 对象,所以这里调用的就是当前 Bean 的

    setPropertyValues(PropertyValues)

    方法,该方法的底层借助于 Java Beans 的

    java.beans.PropertyDescriptor

    属性描述器,获取到对应的写方法,然后通过反射机制设置当前 Bean 的属性值

    总结

    当我们显示或者隐式地调用

    AbstractBeanFactory

    getBean(...)

    方法时,会触发 Bean 的加载,在《开启 Bean 的加载》文章中分析了整个加载过程。

    对于不同作用域的 Bean,底层都会调用

    AbstractAutowireCapableBeanFactory

    createBean(...)

    方法进行创建,在《Bean 的创建过程》文章中分析了整个创建过程。创建 Bean 的过程中,在获取到的一个实例对象后,需要获取相关属性值,然后注入到 Bean 中,其中获取属性值有三种模式:

    • AUTOWIRE_NO,默认,不获取相关属性值

    • AUTOWIRE_BY_NAME,通过名称获取没有定义属性值的**"对象"**的属性值,通过

      getBean(String beanName)

      查找

    • AUTOWIRE_BY_TYPE,通过类型获取没有定义属性值的**"对象"**的属性值,依赖注入的方式

    默认情况下,获取到已定义的属性值后不会通过上面的方式去找属性值,在后续有一个属性值的后置处理,会调用所有的 InstantiationAwareBeanPostProcessor 处理器的 postProcessProperties 方法进行处理,例如 Spring 内部有两个 InstantiationAwareBeanPostProcessor 处理器:

    • AutowiredAnnotationBeanPostProcessor,解析 @Autowired 和 @Value 注解标注的属性,获取对应属性值
    • CommonAnnotationBeanPostProcessor,会解析 @Resource 注解标注的属性,获取对应的属性值

    在获取到所有的属性值后然后通过反射机制设置到 Bean 中

    关于 @Autowired、@Value 和 @Resource 注解的实现原理将在下一篇《@Autowired 等注解的实现原理》文章中进行分析

    赞(0) 打赏
    未经允许不得转载:爱站程序员基地 » 死磕Spring之IoC篇 – Bean 的属性填充阶段