spring那些事 研究IOC容器6-2 (5.1.4.RELEASE)
spring ConstructorResolver#autowireConstructor源码分析
从163行开始,ConstructorResolver会针对多个构造函数进行选择,选择过程如下
1如果已经选出合适的构造函数,直接跳出循环
2如果配置的构造参数小于此次循环中构造函数的参数数量,继续循环
3如果构造参数resolvedValue非空,检查是否添加了Jdk6的@ConstructorProperties,如果添加通过其获取构造函数参数名,如果未添加采用反射方式获取构造函数参数名
4计算参数值(argsHolder.arguments)每个参数类型与构造方法参数列表(paramTypes)中参数的类型差异量,差异量越大表明参数类型差异越大。参数类型差异越大,表明当前构造方法并不是一个最合适的候选项。引入差异量(typeDiffWeight)变量目的:是将候选构造方法的参数列表类型与参数值列表类型的差异进行量化,通过量化后的数值筛选出最合适的构造方法。讲完差异量,再来说说 mbd.isLenientConstructorResolution() 条件。官方的解释是:返回构造方法的解析模式,有宽松模式(lenient mode)和严格模式(strict mode)两种类型可选。具体的细节没去研究,就不多说了。 如果合适,那么改构造方法就时可以将被使用的构造方法
spring ConstructorArgumentValues#addOrMergeGenericArgumentValue源码分析
private void addOrMergeGenericArgumentValue(ValueHolder newValue) {
if (newValue.getName() != null) {
for (Iterator<ValueHolder> it = this.genericArgumentValues.iterator(); it.hasNext();) {
ValueHolder currentValue = it.next();
if (newValue.getName().equals(currentValue.getName())) {
if (newValue.getValue() instanceof Mergeable) {
Mergeable mergeable = (Mergeable) newValue.getValue();
if (mergeable.isMergeEnabled()) {
newValue.setValue(mergeable.merge(currentValue.getValue()));
}
}
it.remove();
}
}
}
this.genericArgumentValues.add(newValue);
}
spring 存在接口Mergeable,它是用来标识一个对象的值可以被后继对象的值覆盖,基于此spring在存放构造函数健-值的时候利用该接口覆盖此前重复配置的值,更确切的应该时删除旧值,添加新值。
以参与构造函数的参数值解析时,ValueHolder 是用来临时存储一组name和value的数据封装对象。BeanDefinition内部持有constructorArgumentValues , 而constructorArgumentValues又持有genericArgumentValues,genericArgumentValues是一个list集合,通过遍历查出具有相同name的ValueHolder ,删除之,再次添加即可。
遗留问题:为什么采用List封装ValueHolder,而不采用hashmap的结构取存储呢?