1.1.5 解析子元素 replace-method
这个方法主要是对 bean 中 replaced-method 子元素的提取,在开始提取分析之前先介绍下这个元素的用法。
方法替换:可以在运行时用新的方法替换现有的方法。与之前 look-up 不同的是,replace-method 不但可以动态地替换返回实体 bean,而且还能动态地更改原有方法的逻辑。
可以看到,无论是 look-up 还是 replaced-method 都是构造了一个 MethodOverride,并最终记录在了 AbstractBeanDefinition 中的 methodOverrides 属性中。关于这个属性的使用以及所提供的的功能后续的文章中会进行详细地总结。
1.1.6 解析子元素 constructor-arg
对构造函数的解析是非常常用的,同时也是非常复杂的,比如下面的构造函数的配置是很常见的:
...
<beans>
<!-- 默认情况下是按照参数的顺序注入,当指定 index 索引后就可以改变注入参数的顺序 -->
<bean id="helloBean" class="com.HelloBean">
<constructor-arg index="0">
<value>林先生</value>
</constructor-arg>
<constructor-arg index="1">
<value>你是最帅的仔!</value>
</constructor-arg>
</bean>
...
</beans>
...
上面的配置是 Spring 构造函数配置中最基础的配置,实现的功能就是对 HelloBean 自动寻找对应的构造函数,并在初始化的时候设置相应的参数。
对于 constructor-arg 子元素的解析,Spring 是通过 parseConstructorArgElements 函数进行解析的,解析过程代码如下:
上面的方法涉及的逻辑其实并不复杂,首先提取 constructor-arg 上必要的属性(index、type、name)。
- 如果配置中指定了 index 属性,那么操作逻辑如下:
1.1 解析 Constructor-arg 的子元素。
1.2 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
1.3 将 type、name、index 属性一并封装在 ConstructorArgumentValues.ValueHolder 类型中并添加至当前 BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValue 属性中。 - 如果没有指定 index 属性,操作步骤如下:
2.1 解析 Constructor-arg 的子元素
2.2 使用 ConstructorArgumentValues.ValueHolder 类型来封装解析出来的元素。
2.3 将 type、name、index 属性一并封装在 ConstructorArgumentValues.ValueHolder 类型中并添加至当前 BeanDefinition 的 constructorArgumentValues 的== genericArgumentValue== 属性中
可以看到,对于是否指定了 index 属性来说, Spring 的处理流程是不同的,关键在于属性信息被保存的位置。
那么了解了整个流程后,进一步了解解析构造函数配置中子元素的过程,进入 parsePropertyValue:
从代码上来看,对构造函数中属性元素的解析,经历了下面几个过程:
- 略过 description 或者 meta。
- 提取 constructor-arg 上的 ref 和 value 属性,以便于根据规则验证正确性,其规则为在 constructor-arg 上不存在以下情况:
1. 同时既有 ref 属性又有 value 属性。
2. 存在 ref 属性或者 value 属性且又有子元素。 - ref 属性的处理。使用 RuntimeBeanReference 封装对应的 ref 名称,如:
<constructor-arg ref="a">
- value 属性的处理。使用 TypedStringValue 封装,如:
<constructor-arg value="a">
- 子元素的处理,如:
<constructor-arg> <map> <entry key="key" value="value"/> </map> </constructor-arg>
而对于子元素的处理,代码如下:
可以看到,在函数中实现了所有可支持的子类的分类处理。到这里已经大致理清了构造函数的解析流程。
1.1.7 解析子元素 property
parsePropertyElements 函数完成了对 property 属性的提取,代码如下:
1.1.8 解析子元素 qualifier
对于 qualifier 元素的获取,我们接触更多的是注解的形式,在使用 Spring 框架进行自动注入时,Spring 容器中匹配的候选 bean 数目必须有且仅有一个。当找不到一个匹配的 bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 bean。
Spring 允许我们通过 Qualifier 指定注入 Bean 的名称,这样歧义就被消除了,而对于配置方式使用如下:
<bean id="myTestBean" class="com.MyTestBean">
<qualifier type="org.Springframework.beans.factory.annotation.Qualifier" value="qf"/>
</bean>
其解析过程与前面类似。
1.2 AbstractBeanDefinition 属性
到这里就完成了对 XML 文档到 GenericBeanDefinition 的转换,也就是说,XML 中所有的配置都可以在 GenericBeanDefinition 的实例类中找到对应的配置。
GenericBeanDefinition 只是子类实现,而大部分的通用属性都保存在了 AbstractBeanDefinition 中。下面看下 AbstractBeanDefinition 的属性来回顾下都解析了哪些对应的配置。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
/**
* Constant for the default scope name: {@code ""}, equivalent to singleton
* status unless overridden from a parent bean definition (if applicable).
*/
public static final String SCOPE_DEFAULT = "";
// 这里省略了静态变量以及 final 常量
/**
* bean 的作用范围,对应 bean 属性 scope
*/
@Nullable
private String scope = SCOPE_DEFAULT;
/**
* 是否是抽象,对应 bean 属性 abstract
*/
private boolean abstractFlag = false;
/**
* 是否延迟加载,对应 bean 属性 lazy-init
*/
private boolean lazyInit = false;
/**
* 自动注入模式,对应 bean 属性 autowire
*/
private int autowireMode = AUTOWIRE_NO;
/**
* 依赖检查,Spring 3.0 后弃用这个属性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
/**
* 用来表示一个 bean 的实例化依靠另一个 bean 先实例化,对应 bean 属性 depend-on
*/
@Nullable
private String[] dependsOn;
/**
* autowire-candidate 属性设置为false, 这样容器在查找自动装配对象时,将不考虑该 bean,
* 即它不会被考虑作为其他 bean 自动装配的候选者,但是该 bean 本身还是可以使用自动装配来注入其他 bean 的
*/
private boolean autowireCandidate = true;
/**
* 自动装配时,当出现多个 bean 候选者时,将作为首选者,对应 bean 属性 primary
*/
private boolean primary = false;
/**
* 用于记录 Qualifier,对应子元素 qualifier
*/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
@Nullable
private Supplier<?> instanceSupplier;
/**
* 允许访问非公开的构造器和方法,程序设置
*/
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为 true,
* 如果为false, 则在以下情况抛出异常:
* interface ITest{}
* class ITestImpl implements ITest{}
* class Main{
* Main(ITest i){}
* Main(ITestImpl i){}
* }
* 因为 Spring 无法准确定位哪个构造函数
* 程序设置
*/
private boolean lenientConstructorResolution = true;
/**
* 对应 bean 属性 factory-bean, 用法:
* <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean"/>
* <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime"/>
*/
@Nullable
private String factoryBeanName;
/**
* 对应 bean 属性 factory-method
*/
@Nullable
private String factoryMethodName;
/**
* 记录构造函数注入属性,对应 bean 属性 constructor-arg
*/
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
/**
* 普通属性集合
*/
@Nullable
private MutablePropertyValues propertyValues;
/**
* 方法重写的持有者,记录 lookup-method, replaced-method 元素
*/
private MethodOverrides methodOverrides = new MethodOverrides();
/**
* 初始化方法,对应 bean 属性 init-method
*/
@Nullable
private String initMethodName;
/**
* 销毁方法,对应 bean 属性 destroy-method
*/
@Nullable
private String destroyMethodName;
/**
* 是否执行 init-method,程序设置
*/
private boolean enforceInitMethod = true;
/**
* 是否执行 destroy-method,程序设置
*/
private boolean enforceDestroyMethod = true;
/**
* 是否是用户定义的,而不是应用程序本身定义的,创建 AOP 时为true,程序设置
*/
private boolean synthetic = false;
/**
* 定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关,SUPPORT:某些复杂配置的一部分
* 程序设置
*/
private int role = BeanDefinition.ROLE_APPLICATION;
/**
* bean 的描述信息
*/
@Nullable
private String description;
/**
* 这个 bean 定义的资源
*/
@Nullable
private Resource resource;
}