Spring IoC 属性赋值阶段
前言
本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本。因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析。
本篇文章主要介绍 Spring IoC 容器中 bean 的属性赋值阶段。
正文
我们在Spring IoC bean 的创建一文中分析创建 bean 实例的主要流程,此时创建出来的 bean 还是个属性未赋值的实例,在创建完之后会进入 populateBean() 方法,即进入属性赋值阶段。我们简单回顾一下,上次分析过的 doCreateBean() 方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
    // 实例化 bean
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        // 如果bean的作用域是singleton,则需要移除未完成的FactoryBean实例的缓存
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 通过构造函数反射创建bean的实例,但是属性并未赋值,见下文详解
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 获取bean的实例
    final Object bean = instanceWrapper.getWrappedInstance();
    // 获取bean的类型
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                // BeanDefinition 合并后的回调,见下文详解
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            // 省略异常处理...
            mbd.postProcessed = true;
        }
    }
    // bean的作用域是单例 && 允许循环引用 && 当前bean正在创建中
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    // 如果允许bean提前曝光
    if (earlySingletonExposure) {
        // 将beanName和ObjectFactory形成的key-value对放入singletonFactories缓存中
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
    Object exposedObject = bean;
    try {
        // 给 bean 的属性赋值
        populateBean(beanName, mbd, instanceWrapper);
        // 初始化 bean
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    // 省略部分代码
}
属性赋值
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 {
            return;
        }
    }
    // 给InstantiationAwareBeanPostProcessors最后一次机会在属性设置前来改变bean
    // 例如:可以用来支持属性注入的类型
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                // 这里会调用bean实例化后的生命周期回调,返回false会跳过下面的属性赋值阶段
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    return;
                }
            }
        }
    }
    // 获取PropertyValues
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // 获取依赖注入类型
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
  	// 如果依赖注入类型是 byName 或者 byType
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      	// 赋值pvs到可修改的MutablePropertyValues
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 根据名称自动注入,见下文详解
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 根据类型自动注入,见下文详解
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    // 是否有注册InstantiationAwareBeanPostProcessors的实现类
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        // 遍历并找到InstantiationAwareBeanPostProcessor的实现类,调用处理属性值的后置处理方法
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                    }
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    // 如果属性值的后置处理方法返回null,直接返回,不会进行底下的属性值应用阶段
                    if (pvsToUse == null) {
                        return;
                    }
                }
                pvs = pvsToUse;
            }
        }
    }
    if (needsDepCheck) {
        if (filteredPds == null) {
            filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        }
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }
    if (pvs != null) {
        // 属性填充,见下文详解
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}
上面方法首先会调用 bean 的实例化后生命周期回调方法,如果返回 false 会跳过下面的属性赋值阶段。关于 InstantiationAwareBeanPostProcessors 接口在Spring IoC bean 的创建一文中介绍过,这里不再赘述。接着判断是否是按 名称 或者 类型 自动注入属性并填入 newPvs 中,接着调用 bean 属性填充前的生命周期回调。属性填充前生命周期回调方法有两个 postProcessProperties() 和 postProcessPropertyValues(),第一个是 Spring 5.1 新加的,后面的是老的,已经被标记为过时;首先会调用 postProcessProperties() 如果返回空调用 postProcessPropertyValues(),否则直接使用返回的 PropertyValues;postProcessPropertyValues() 如果返回空会直接跳过属性填充阶段,不为空直接使用返回的 PropertyValues。
按照名称依赖注入
AbstractAutowireCapableBeanFactory#autowireByName
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    // 寻找bw中需要依赖注入的属性名称
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    // 遍历需要注入的bean
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
          	// 调用getBean()方法获取bean
            Object bean = getBean(propertyName);
            // 将需要注入bean的实例加入到pvs
            pvs.add(propertyName, bean);
            // 注册依赖关系
            registerDependentBean(propertyName, beanName);
        }
    }
}
上面的方法很简单,就是寻找 bean 的非简单类型并且不存在于 mbd.getPropertyValues() 中的属性,然后遍历调用 getBean() 方法去获取实例,完成注入。
非简单类型就是指除去8个原始类型、String类型、Number类型、Date类型、URL类型、URI类型的其它类型。
registerDependentBean() 方法在Spring IoC bean 的加载一文中有分析过,这里不再赘述。
按照类型依赖注入
AbstractAutowireCapableBeanFactory#autowireByType
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    // 获取bean中非简单属性
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // 根据类型注入永远不要注入Object类型,你细细地品一下
            if (Object.class != pd.getPropertyType()) {
                // 获取属性的可写方法,一般是set方法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                // 依赖解决,最后返回符合条件需要注入的bean实例
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    // 需要注入的bean实例不为空,加入到pvc
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    // 注册依赖关系
                    registerDependentBean(autowiredBeanName, beanName);
                }
                autowiredBeanNames.clear();
            }
        } catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}
上面方法中的 resolveDependency() 方法在Spring IoC bean 的创建一文中介绍过,这里不再赘述。
属性赋值
AbstractAutowireCapableBeanFactory#applyPropertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // 属性为空,直接返回
    if (pvs.isEmpty()) {
        return;
    }
    if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
        ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
    }
    MutablePropertyValues mpvs = null;
    List<PropertyValue> original;
    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
        // 快捷方式,如果属性已经转换过,直接填充进BeanWrapper
        if (mpvs.isConverted()) {
            try {
                bw.setPropertyValues(mpvs);
                return;
            } catch (BeansException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
            }
        }
        // 属性没有转换过,获取属性列表
        original = mpvs.getPropertyValueList();
    } else {
        // 获取属性列表
        original = Arrays.asList(pvs.getPropertyValues());
    }
    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }
    // 获取对应的解析器
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    // 创建深拷贝,解决引用的问题
    List<PropertyValue> deepCopy = new ArrayList<>(original.size());
    boolean resolveNecessary = false;
    // 遍历属性,将属性转换为对应的类型
    for (PropertyValue pv : original) {
        // 如果pv类型转换过,直接添加进deepCopy
        if (pv.isConverted()) {
            deepCopy.add(pv);
        } else {
            // 进行转换
            // 拿到pv原始属性名和属性值
            String propertyName = pv.getName();
            Object originalValue = pv.getValue();
            if (originalValue == AutowiredPropertyMarker.INSTANCE) {
                Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
                if (writeMethod == null) {
                    throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
                }
                originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
            }
            // 进行类型转换
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
            Object convertedValue = resolvedValue;
            boolean convertible = bw.isWritableProperty(propertyName) &&
                !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
            if (convertible) {
                // 如果可转换,则转换指定目标属性的给定值
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
            // 在合并的BeanDefinition中存储转换后的值,以避免为每个创建的bean实例重新转换
            if (resolvedValue == originalValue) {
                if (convertible) {
                    pv.setConvertedValue(convertedValue);
                }
                deepCopy.add(pv);
            } else if (convertible && originalValue instanceof TypedStringValue &&
                       !((TypedStringValue) originalValue).isDynamic() &&
                       !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                pv.setConvertedValue(convertedValue);
                deepCopy.add(pv);
            } else {
                resolveNecessary = true;
                deepCopy.add(new PropertyValue(pv, convertedValue));
            }
        }
    }
    if (mpvs != null && !resolveNecessary) {
        mpvs.setConverted();
    }
    try {
        // 填充bean属性值
        bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    } catch (BeansException ex) {
        throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    }
}
上面代码中的 bw.setPropertyValues()  方法最终会调用 BeanWrapperImpl#setVlaue() 方法,如下:
public void setValue(final @Nullable Object value) throws Exception {
    // 这里一般就是set方法
    final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor)this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod());
    // 利用反射调用set方法给属性赋值
    ReflectionUtils.makeAccessible(writeMethod);
    writeMethod.invoke(getWrappedInstance(), value);
}
下图是我 debug 时的截图,可以看到基本上就是在调用属性的 setter 方法:

注意:没有
setter方法时会抛出异常。
总结
本篇文章主要分析了 Spring IoC 的属性赋值阶段的流程,Spring 在此阶段也提供了2个扩展点;分别是 bean 的实例化后和属性赋值前,即 InstantiationAwareBeanPostProcessor 接口的 postProcessAfterInstantiation() 方法和 postProcessProperties() 方法。需要注意的是在 XML 中配置的 autowire 属性,不管是 byName 还是 byType 都需要 setter 方法,但是我们平时在使用 @Autowire 注解时并不需要 settter 方法,原因会在分析 @Autowire 注解时讲述。
Spring IoC 属性赋值阶段的更多相关文章
- Spring IoC @Autowired 注解详解
		
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 我们平时使用 Spring 时,想要 依赖 ...
 - 死磕Spring之IoC篇 - 深入了解Spring IoC(面试题)
		
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
 - Spring IoC createBean 方法详解
		
前言 本篇文章主要分析 Spring IoC 的 createBean() 方法的流程,以及 bean 的生命周期. 下面是一个大致的流程图: 正文 AbstractAutowireCapableBe ...
 - Spring IoC 循环依赖的处理
		
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 是 ...
 - Spring IoC bean 的初始化
		
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 本篇文章主要介绍 Spring IoC 容 ...
 - 【小家Spring】Spring IoC是如何使用BeanWrapper和Java内省结合起来给Bean属性赋值的
		
#### 每篇一句 > 具备了技术深度,遇到问题可以快速定位并从根本上解决.有了技术深度之后,学习其它技术可以更快,再深入其它技术也就不会害怕 #### 相关阅读 [[小家Spring]聊聊Sp ...
 - Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段
		
目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...
 - [原创]java WEB学习笔记98:Spring学习---Spring Bean配置及相关细节:如何在配置bean,Spring容器(BeanFactory,ApplicationContext),如何获取bean,属性赋值(属性注入,构造器注入),配置bean细节(字面值,包含特殊字符,引用bean,null值,集合属性list map propert),util 和p 命名空间
		
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
 - Spring IOC 容器源码分析 - 填充属性到 bean 原始对象
		
1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...
 
随机推荐
- Java实现 蓝桥杯VIP 算法提高 夺宝奇兵
			
算法提高 夺宝奇兵 时间限制:1.0s 内存限制:512.0MB [题目描述] 在一座山上,有很多很多珠宝,它们散落在山底通往山顶的每条道路上,不同道路上的珠宝的数目也各不相同.下图为一张藏宝地图: ...
 - lambda表达式操作DataTable
			
using System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Text; ...
 - sql server 连接种类
			
一.连接种类 内连接 inner join 如果分步骤理解的话,内连接可以看做先对两个表进行了交叉连接后,再通过加上限制条件(SQL中通过关键字on)剔除不符合条件的行的子集,得到的结果就是内连接了. ...
 - yum安装配置MySQL数据库
			
1.配置yum源 # 先安装wget yum install wget -y 2.下载mysql源安装包 wget http://dev.mysql.com/get/mysql57-commu ...
 - Android拍照相关知识总结
			
1.调用系统的照相机程序 Intent intent = newIntent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(inte ...
 - sorted排序
			
sorted(['bob', 'about', 'Zoo', 'Credit']) # ['Credit', 'Zoo', 'about', 'bob'] ''' 默认情况下,对字符串排序,是按照AS ...
 - yaml读取封装
			
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 对yaml格式的配置文件的操作 """ ...
 - loadrunner安装负载机
			
1,安装docker 2,下载最新版本的load_generator镜像,命令如下: docker pull hpsoftware/load_generator 3,load_generator镜像实 ...
 - 技术周刊 · Lighthouse 测试报告生成
			
登高远眺 天高地迥,觉宇宙之无穷 基础技术 Lighthouse 测试内幕 文章分享了网易云音乐前端性能监控平台使用 Lighthouse 的实践经验,介绍了 Lighthouse 的测试流程.内部模 ...
 - VMware历史版本下载【1.0~3.0】
			
前提:此为走HTTP协议的FTP伺服器,而且有直到Vmware3.0[之后就没了]的版本 link:http://linux.mathematik.tu-darmstadt.de/pub/linux/ ...