前言:Bean的创建所经历的步骤大致为实例化,填充属性,初始化。之前在Spring第九天的时候描述过实例化的过程了,所以这篇文章来描述Bean的填充属性环节
入口方法:AbstractAutowireCapableBeanFactory类的populateBean(beanName, mbd, instanceWrapper)方法。
1.首先属性的类型可以分为大致这么几类
- 8种基本数据类型
- 引用类型
- 集合类型,集合类型的元素可以为基本数据类型与引用类型
2.属性注入的方式,根据Spring源码可以得出有5种,在AutowireCapableBeanFactory类中可以查看
- AUTOWIRE_NO=0:默认,表示不选择自动装配
- AUTOWIRE_BY_NAME=1:表示按名称进行自动注入
- AUTOWIRE_BY_TYPE=2:表示按类型进行自动注入
- AUTOWIRE_CONSTRUCTOR=3:按构造器进行注入
- AUTOWIRE_AUTODETECT=4:自动选择
3.填充属性详细介绍
- 实例化对象为空,但是BeanDefinition中却有属性键值对信息,就抛出异常
if (bw == null) {
// 如果mbd有需要设置的属性
if (mbd.hasPropertyValues()) {
// 抛出bean创建异常
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
// 没有可填充的属性,直接跳过
return;
}
}
- 容器中是否存在InstantiationAwareBeanPostProcessor及其子类,该类是用于丰富Bean信息的类,可以在Bean的实例化前后,初始化前后,及其属性设置上进行操作,如果存在这种类型的后置处理器,就调用他们的实例化后要执行的丰富postProcessAfterInstantiation()
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//遍历工厂中的BeanPostProcessor对象
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果 bp 是 InstantiationAwareBeanPostProcessor 实例
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// postProcessAfterInstantiation:一般用于设置属性
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
- 判断xml文件中定义Bean信息的时候是否有显示的设置<property/>,如果有的话就保存在PropertyValues对象中
//PropertyValues:包含以一个或多个PropertyValue对象的容器,通常包括针对特定目标Bean的一次更新
//如果mdb有PropertyValues就获取其PropertyValues
// xml配置文件中的<property/>获取到该标签的键值对
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
- 根据注入方式选择对应的方法去获取键值对的信息,主要是根据名称注入与类型注入两种方式,文章最后会附上一张流程图,会给出autowiredByName方式的处理流程
// 获取 mbd 的 自动装配模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果 自动装配模式 为 按名称自动装配bean属性 或者 按类型自动装配bean属性
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//MutablePropertyValues:PropertyValues接口的默认实现。允许对属性进行简单操作,并提供构造函数来支持从映射 进行深度复制和构造
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根据autotowire的名称(如适用)添加属性值
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
//通过bw的PropertyDescriptor属性名,查找出对应的Bean对象,将其添加到newPvs中
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 根据自动装配的类型(如果适用)添加属性值
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//通过bw的PropertyDescriptor属性类型,查找出对应的Bean对象,将其添加到newPvs中
autowireByType(beanName, mbd, bw, newPvs);
}
//让pvs重新引用newPvs,newPvs此时已经包含了pvs的属性值以及通过AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE自动装配所得到的属性值
pvs = newPvs;
}
- 调用InstantiationAwareBeanPostProcessor及其子类的postProcessPropertyValues()方法,以针对属性进行一些操作
//@autoWired注解的注入工作
if (hasInstAwareBpps) {
//如果pvs为null
if (pvs == null) {
//尝试获取mbd的PropertyValues
pvs = mbd.getPropertyValues();
}
//遍历工厂内的所有后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果 bp 是 InstantiationAwareBeanPostProcessor 的实例
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//将bp 强转成 InstantiationAwareBeanPostProcessor 对象
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//postProcessProperties:在工厂将给定的属性值应用到给定Bean之前,对它们进行后处理,不需要任何属性扫描符。该回调方法在未来的版本会被删掉。
// -- 取而代之的是 postProcessPropertyValues 回调方法。
// 让ibp对pvs增加对bw的Bean对象的propertyValue,或编辑pvs的proertyValue
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
//如果pvs为null
if (pvsToUse == null) {
//如果filteredPds为null
if (filteredPds == null) {
//mbd.allowCaching:是否允许缓存,默认时允许的。缓存除了可以提高效率以外,还可以保证在并发的情况下,返回的PropertyDesciptor[]永远都是同一份
//从bw提取一组经过筛选的PropertyDesciptor,排除忽略的依赖项或忽略项上的定义的属性
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//postProcessPropertyValues:一般进行检查是否所有依赖项都满足,例如基于"Require"注释在 bean属性 setter,
// -- 替换要应用的属性值,通常是通过基于原始的PropertyValues创建一个新的MutablePropertyValue实例, 添加或删除特定的值
// -- 返回的PropertyValues 将应用于bw包装的bean实例 的实际属性值(添加PropertyValues实例到pvs 或者 设置为null以跳过属性填充)
//回到ipd的postProcessPropertyValues方法
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
//如果pvsToUse为null,将终止该方法精致,以跳过属性填充
if (pvsToUse == null) {
return;
}
}
//让pvs引用pvsToUse
pvs = pvsToUse;
}
}
}
要注意的是,以上步骤,除了InstantiationAwareBeanPostProcessor及其子类的内部实现逻辑我们不得而知。其他的方式都没有进行属性的赋值,只是寻找需要注入的属性,并将属性和值保存到PropertyValues对象中。
- 最后将PropertyValues中的键值对进行属性注入操作
//如果pvs不为null
if (pvs != null) {
//应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用。必须使用深拷贝,所以我们 不会永久地修改这个属性
applyPropertyValues(beanName, mbd, bw, pvs);
}
最后,附上流程图