章节目录
Spring推断构造函数中自动装配构造函数过程里的构造函数参数权重计算
我们知道,在Spring的refresh()步骤中进行单例bean的初始化,在bean的初始化过程中,也就涉及到进行最合适的构造函数的推断,本文也将介绍构造函数推断中,进行构造函数参数权重计算的部分,详细的代码位置位于方法:
org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor(String beanName, RootBeanDefinition mbd,@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs)
代码说明
在方法中,进行权重比较的代码为
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
这句话的含义在为:如果在bean定义中设置构造函数的解析为宽松模式,则使用getTypeDifferenceWeight计算权重,否则使用getAssignabilityWeight计算权重。构造函数解析的默认为宽松模式。
由此,我们在此介绍getTypeDifferenceWeight
和getAssignabilityWeight
的两种不同的权重计算方式
getTypeDifferenceWeight 根据参数对象类型同参数类型的差得到权重
/**
*得到参数同参数类型的差异权重
* @param paramTypes 参数类型集合
* @return 权重差值
*/
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// 如果找到有效的参数,请确定类型差异权重。
// 尝试在转换后的参数和原始参数上键入不同的权重。
// 如果原始参数权重更好,使用它。
// 将原始参数权重减少1024,使其优于同等的转换权重。
// 获取参数值同参数类型比较之后的权重
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
// 获取原参数值同参数类型比较之后的权重,并减去1024,标识优先使用原参数
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
// 比较得到最优的权重差值
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
这个方法中调用了两次MethodInvoker.getTypeDifferenceWeight
分别计算转换之后的参数对象同参数类型比较的权重和原对象类型同参数类型比较的权重,并且在原对象比较权重-1024的基础上同转换后的参数对象比较权重相比,取最优的权重差值。
下面我们看下这个用于进行关键权重计算的方法MethodInvoker.getTypeDifferenceWeight
/**
* 判断候选方法的声明参数类型与该方法应该使用的特定参数列表之间的匹配的算法。
* <p>确定表示类型和参数之间的类层次结构差异的权重。
* 直接匹配,即类型为Integer -> 类Integer的参数,不会增加结果 — 所有直接匹配意味着权重为0。
* 类型Object和类Integer的arg之间的匹配将增加2的权重,因为层次结构中的向上2步的超类(即,Object)是最后一个仍然匹配所需类型对象的。
* 类型数量和类整数Integer将增加1权重,因此,由于层次结构中的向上1步的超类加强(即数字)仍然匹配所需的型号,一个整数类型的参数,
* 构造函数(Integer)会倾向于一个构造函数(Number),反过来会倾向于构造函数(Object)。所有的参数权值都被累加。
* <p>Determines a weight that represents the class hierarchy difference between types and
* arguments. A direct match, i.e. type Integer -> arg of class Integer, does not increase
* the result - all direct matches means weight 0. A match between type Object and arg of
* class Integer would increase the weight by 2, due to the superclass 2 steps up in the
* hierarchy (i.e. Object) being the last one that still matches the required type Object.
* Type Number and class Integer would increase the weight by 1 accordingly, due to the
* superclass 1 step up the hierarchy (i.e. Number) still matching the required type Number.
* Therefore, with an arg of type Integer, a constructor (Integer) would be preferred to a
* constructor (Number) which would in turn be preferred to a constructor (Object).
* All argument weights get accumulated.
*
* <p>注意:这是MethodInvoker本身使用的算法,也是Spring bean容器中用于构造函数和工厂方法选择的算法(如果构造函数解析很宽松,这是常规bean定义的默认解析)。
* @param paramTypes 要匹配的参数类型
* @param args 要匹配的参数
* @return 所有参数的累计权重
*/
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) {
int result = 0;
for (int i = 0; i < paramTypes.length; i++) {