判断可否使用缓存中的构造器
// Shortcut when re-creating the same bean...
// 标记是否有缓存的构造方法
boolean resolved = false;
// 缓存的构造器是否有参数,如果没有表示:需要自动匹配
boolean autowireNecessary = false;
// 如果没有参数
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 已经缓存的构造方法或者工厂方法(Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,
// 避免再次创建相同bean时再次解析)
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 表示有缓存的构造方法,利用已经解析好的构造方法去实例化对象
if (resolved) {
if (autowireNecessary) {
// 构造器有参数,构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
} else {
// 默认构造函数
return instantiateBean(beanName, mbd);
}
}
从bean后置处理器中为自动装配寻找构造方法
// Candidate constructors for autowiring?
// 从bean后置处理器中为自动装配寻找构造方法,比如:AutowiredAnnotationBeanPostProcessor
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
通过 determineConstructorsFromBeanPostProcessors 得到扩展的构造方法。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
找出最合适的构造方法
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, null);
}
🔥 autowireConstructor
上面的推断方式最终还是会走到这个方法,利用带参数的构造函数去实例化对象,是最复杂的一种,因为不确定太多。所以这块的代码相当的长了。
首先开发者可以通过什么方式来指定使用哪个构造方法呢?
https://www.jb51.net/article/264134.htm
- 通过xml中的
标签,这个标签表示构造方法参数,所以可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法; - 通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值;
- 如果Bean为注解@Lazy修饰的或者非单例的,可以通过getBean方法设置构造方法的入参,达到指定构造方法的效果。如,applicationContext.getBean(“BeanDemo”, new CircularRefA());【同理,获取beanDefinition,使用beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new CircularRefA());指定构造方法参数】
接下来解析这块复杂的代码。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireConstructor
protected BeanWrapper autowireConstructor(String beanName
, RootBeanDefinition mbd
, @Nullable Constructor<?>[] ctors
, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
org.springframework.beans.factory.support.ConstructorResolver#autowireConstructor
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 如果有构造函数的参数直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
} else {
// 没有尝试从缓存中得到
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 从缓存中得到了参数
if (argsToResolve != null) {
// 解析参数类型,比如 Student(int,int),通过此方法将参数从("1","1")转换成(1,1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
// 缓存中没有
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
// 如果参数没有给构造函数,那么尝试从定义中获取
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
// 如果只有一个构造函数,并且没有参数。那就是默认的构造函数了。
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// 判断是否需要自动装配
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
// 持有构造器的参数和值
ConstructorArgumentValues resolvedValues = null;
// 最少参数的个数
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
} else {
// 获取解析阶段得到的构造函数信息
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析构造器的参数和值,从而得到构造器使用最少参数的数量
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 排序给定的构造函数,public构造函数优先参数数量降序、非public构造函数参数数量降序
AutowireUtils.sortConstructors(candidates);
// 最小差异值
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历所有构造函数,找到最合适的
for (Constructor<?> candidate : candidates) {
// 当前构造函数参数的数量
int parameterCount = candidate.getParameterCount();
// 如果 constructorToUse argsToUse 不空,并且 参数数量够用,就不用继续找了
if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
// 参数比最小参数还小,不够用,继续找
if (parameterCount < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
// 参数类型的数组
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
try {
// 从注解上获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
// 获取配置的参数名称
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
} catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
} else {
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 如果是宽松模式就走方法getTypeDifferenceWeight;否则走getAssignabilityWeight
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
} else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// 如果遍历了所有的构造函数,依然没有找到,就要记录异常了
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
} else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
// 存在不能直接访问的构造函数,并且不是宽松的访问 ,那么异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
// 解析得到的参数加入缓存
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
// 实例化
Assert.state(argsToUse != null, "Unresolved constructor arguments");
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
构造函数创建对象,最终都会来到这个方法,ConstructorResolver#autowireConstructor ,风格不像前面的套路,getBean、doGetBean、createBean、doCreateBean,都是 XX ,doXX,一层一层嵌套,比较容易理解。这个方法有点复杂,代码太长……
梳理下过程:
步骤 | 说明 |
---|---|
1. 确定构造函数的参数 |
1. 如果 explicitArgs 参数不为空的话就可以直接使用该参数,因为这个参数是用户在 getBean 的时候指定的; 2. explicitArgs 为空,那么尝试去缓存中获取,缓存的格式不确定,所以需要用方法 resolvePreparedArguments 将参数转换 (比如:Student(int,int),通过此方法将参数从(“1”,”1”) 转换成(1,1) ) 3. 缓存中也没有的话,就去解析 BeanDefinition 。 |
2. 确定构造函数 |
采用参数个数和类型匹配的方式。 1. 同样如果参数没有构造函数,那么解析 BeanDefinition 得到; 2. 如果发现只有一个构造函数并且没有参数,可以确定是默认无参构造,可以直接实例化; 3. 解析 BeanDefinition 得到构造函数的参数信息,利用方法 resolveConstructorArguments 转换构造函数的参数类型 resolvedValues 和确定参数的个数 minNrOfArgs; 4. 给构造函数排个序( public 构造函数优先参数数量降序、非 public 构造函数参数数量降序); 5. 然后分别就每一个构造函数进行排查: 1. 参数个数比minNrOfArgs小,参数不够,排除; 2. 如果 resolvedValues 不为空,获取当前构造函数的参数名称,将结果放到 argsHolder;如果为空,并且 explicitArgs 不为空,那么将 explicitArgs 放到 argsHolder;否则继续找一个构造函数; 3. 得到当前构造函数的参数相关信息后,开始比对是否合适。如果是宽松对比模式那么对比类型 argsHolder.getTypeDifferenceWeight;否则对比 argsHolder.getAssignabilityWeight,得到一个差异值; 4. 得到的差异值和默认最小差异值对比,如果较小,那么当前构造函数就是可用的。否则记录相关信息到 ambiguousConstructors。 |
3. 记录异常 |
如果经过上一步,仍然没有找到合适的构造函数,那么打印相关信息。 |
4. 实例化对象 |
没有问题的话,根据构造函数及参数去实例化对象。 |
确定构造函数的参数
// 如果有构造函数的参数直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
} else {
// 没有尝试从缓存中得到
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 从缓存中得到了参数
if (argsToResolve != null) {
// 解析参数类型,比如 Student(int,int),通过此方法将参数从("1","1")转换成(1,1)
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
首先判断方法是否传递了参数 explicitArgs ,这个参数是通过代码指定的,并非从配置文件而来,所以如果这个参数存在的话,那么应该使用的构造函数和参数就是确定的,不用再解析了。
如果这个参数不存在的话,就去缓存找构造函数和参数,查询到需要对缓存的数据进行解析,通过方法 resolvePreparedArguments。查询不到的话就去解析 Beandefinition。
解析其实就是把 argsToResolve 解析到 argsToUse,如下所示:
argsToResolve = mbd.preparedConstructorArguments;
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
得到所有构造函数
有了参数之后,开始确定到底使用哪个构造函数。
同样构造函数可以通过方法传递进来,如果没有的话,那么也是从 BeanDefinition 缓存中获取(可能有多个)
如果判断只有一个构造函数,并且还没有参数,别无选择,只能使用这个唯一构造函数去实例化。
大多数情况下可能有多个构造函数:
得到构造函数的参数个数 minNrOfArgs。
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
} else {
// 获取解析阶段得到的构造函数信息
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 解析构造器的参数和值,从而得到构造器使用最少参数的数量
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
这个是我们在 BeanDefinition 解析阶段解析标签得到的数据。系统默认标签解析-解析 constructor-arg 标签。
然后通过方法 resolveConstructorArguments 解析里面参数,将解析的结果放到 resolvedValues 中,同时统计了参数个数。
private int resolveConstructorArguments(String beanName
, RootBeanDefinition mbd
, BeanWrapper bw
, ConstructorArgumentValues cargs
, ConstructorArgumentValues resolvedValues) {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
// 参数数量的最小值,默认是按照索引配置的参数的数量 + 按照名称配置的参数的数量
/*
<bean id="pig" class="cn.lichenghao.createBeanInstance.entity.Pig">
<constructor-arg name="id" value="红猪"></constructor-arg>
<constructor-arg index="1" value="222"></constructor-arg>
<constructor-arg index="2" value="222"></constructor-arg>
<constructor-arg index="3" value="222"></constructor-arg>
</bean>
或者
<bean id="pig" class="cn.lichenghao.createBeanInstance.entity.Pig">
<constructor-arg index="0" value="222"></constructor-arg>
<constructor-arg index="1" value="222"></constructor-arg>
<constructor-arg name="age" value="111"></constructor-arg>
<constructor-arg index="3" value="222"></constructor-arg>
</bean>
*/
int minNrOfArgs = cargs.getArgumentCount(); //4
// 遍历根据位置配置的参数
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
int index = entry.getKey();
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid constructor argument index: " + index);
}
if (index + 1 > minNrOfArgs) {
minNrOfArgs = index + 1;
}
// 参数的值没有转换的话,进行转换,记录在resolvedValues中
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
} else {
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
// 参数的值没有转换的话,进行转换,记录在resolvedValues中
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
} else {
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
return minNrOfArgs;
}
给构造函数排个序。
排序规则:public构造函数优先参数数量降序、非public构造函数参数数量降序。
AutowireUtils.sortConstructors(candidates);
public static void sortConstructors(Constructor<?>[] constructors) {
Arrays.sort(constructors, EXECUTABLE_COMPARATOR);
}
public static final Comparator<Executable> EXECUTABLE_COMPARATOR = (e1, e2) -> {
int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers()));
return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount());
};
得到每个构造函数的参数信息
这一步会变量所有的构造函数,得到每个构造函数的参数相关信息。
for (Constructor<?> candidate : candidates) {
........
}
获取构造函数参数的数量 parameterCount,如果比 minNrOfArgs 还小,参数不够啊,继续找下一个;
int parameterCount = candidate.getParameterCount();
// 参数比最小参数还小,不够用,继续找
if (parameterCount < minNrOfArgs) {
continue;
}
判断 resolvedValues :
ArgumentsHolder argsHolder;
// 参数类型的数组
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
try {
// 从注解上获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
// 获取配置的参数名称
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
} catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
} else {
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
分成不同的分支:
分支 | 说明 |
---|---|
resolvedValues==null | 说明用户可能在 getBean 环节提供了构造函数的参数,那么判断下参数个数是否等于用户给定的 explicitArgs 参数个数,不等判断下一个构造函数;相等的话,就留下来,继续后面的对比。 |
resolvedValues==null && 没有提供相关 explicitArgs | 说明用户没有配置构造函数的参数,也就意味着后面的逻辑都不会走。直接都不用判断了,会直接走无参构造。 |
resolvedValues != null | 解析构造函数的参数名称。 |
如果 resolvedValues != null 那么需要进一步解析得到当前构造函数的参数名称信息。有如下两种方式得到。
第一种方式:
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
利用注解的方式
@ConstructorProperties({“x”, “y”})
public Point(int x, int y) {
this.x = x;
this.y = y;
}
org.springframework.beans.factory.support.ConstructorResolver.ConstructorPropertiesChecker
private static class ConstructorPropertiesChecker {
@Nullable
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
if (cp != null) {
String[] names = cp.value();
if (names.length != paramCount) {
throw new IllegalStateException("Constructor annotated with @ConstructorProperties but not " +
"corresponding to actual number of parameters (" + paramCount + "): " + candidate);
}
return names;
} else {
return null;
}
}
}
第二种方式:
直接解析构造函数中定义的参数名称。
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
到此,先整理下,我们都得到了哪些信息:
- BeanDefinition 信息;
- BeanWrapperImpl bean 包装对象;
- resolvedValues,配置文件中配置的构造函数参数信息;
- 当前构造函数参数的类型 paramTypes,如: [String,String];
- 当前构造函数参数的名称 paramNames,如: [x,y];
将解析后的数据,利用 createArgumentArray 封装到 ArgumentsHolder ,然后继续下一步的判断。
argsHolder = createArgumentArray(beanName
, mbd
, resolvedValues
, bw
, paramTypes
, paramNames
, getUserDeclaredConstructor(candidate)
, autowiring
, candidates.length == 1);
其中方法 getUserDeclaredConstructor 用于判断 candidate 构造函数是否是 cglib 代码对象的构造函数,如果是的话,返回原始对象的构造函数。
protected Constructor<?> getUserDeclaredConstructor(Constructor<?> constructor) {
// 获取构造函数对应的Class对象
Class<?> declaringClass = constructor.getDeclaringClass();
// 如果是 cglib 代理类,返回原始 Class
Class<?> userClass = ClassUtils.getUserClass(declaringClass);
// 不等说明constructor是cglib代理类的构造函数
if (userClass != declaringClass) {
try {
// 获取原始Class中的构造函数
return userClass.getDeclaredConstructor(constructor.getParameterTypes());
} catch (NoSuchMethodException ex) {
// No equivalent constructor on user class (superclass)...
// Let's proceed with the given constructor as we usually would.
}
}
return constructor;
}
那么继续进入方法 createArgumentArray .
对比构造函数是否满足
对比有两种模式,一种 lenientConstructorResolution = true 宽松模式, 另外一种是 lenientConstructorResolution = false,分别通过 getTypeDifferenceWeight 和 getAssignabilityWeight 计算出对应的差异值。
getTypeDifferenceWeight
比较参数值的类型。
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
// Decrease raw weight by 1024 to prefer it over equal converted weight.
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
重载方法
org.springframework.util.MethodInvoker#getTypeDifferenceWeight
public static int getTypeDifferenceWeight(Class<?>[] paramTypes, Object[] args) {
int result = 0;
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], args[i])) {
// 如果args[i]==null 并且 paramTypes[i] 是基本类型
// 如果args[i]!=null 并且 args[i]不是paramTypes[i]同类,也不是子类
// 说明不是空,就是类型根本一点边都不着
return Integer.MAX_VALUE;
}
if (args[i] != null) {
// 参数类型
Class<?> paramType = paramTypes[i];
// 参数值的父类
Class<?> superClass = args[i].getClass().getSuperclass();
while (superClass != null) {
if (paramType.equals(superClass)) {
result = result + 2;
superClass = null;
} else if (ClassUtils.isAssignable(paramType, superClass)) {
result = result + 2;
superClass = superClass.getSuperclass();
} else {
superClass = null;
}
}
if (paramType.isInterface()) {
result = result + 1;
}
}
}
return result;
}
遍历参数类型,开始分析每个参数值。
第一种情况:
args[i]==null 并且 paramTypes[i] 是基本数据类型;那么直接返回 Integer.MAX_VALUE;
args[i]!=null 并且 args[i] 不是 paramTypes[i] 同类,也不是子类;
第二种情况 args[i]!=null
获取参数类型 Class<?> paramType = paramTypes[i];
获取参数值的父类型 Class<?> superClass = args[i].getClass().getSuperclass();
如果 superClass!=null ,开始循环判断当前参数值的每一个父类:
- 如果 paramType==superClass的话,那么匹配度+2,结束循环;
- 如果 ClassUtils.isAssignable(paramType, superClass) 匹配度+2,继续比较该父类的父类,相当于一个父类就+2;
- 如果以上都不满足,结束循环。
如果参数的类型为接口类型,那么匹配度+1。
依次比较每一个参数类型和参数值类型,最终得到 typeDiffWeight。
上面的文字描述感觉晕晕的,可以用一段代码来验证测试下。
假如我们有如下类:A extend B implements D ;B etend C
public class A extends B implements D {
public static void main(String[] args) {
Object[] myArgs = new Object[]{new A()};
// 参数类型为A,完全匹配 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, myArgs));
// 参数类型为B,父类匹配 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, myArgs));
// 参数类型为C,父父匹配 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, myArgs));
// 参数类型为D,接口匹配 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, myArgs));
}
}
public class B extends C{
}
public class C {
}
public interface D {
}
好,回到方法。分别用 arguments 和 rawArguments 做了比对。
这俩参数的区别:
arguments:参数类型是经过转换的,比如:xx(String,String) ——> xx(12(Integer),”122”(String))
rawArguments:原始的可能是 xx(String,String)
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
// Decrease raw weight by 1024 to prefer it over equal converted weight.
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
getAssignabilityWeight
public int getAssignabilityWeight(Class<?>[] paramTypes) {
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
return Integer.MAX_VALUE;
}
}
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], this.rawArguments[i])) {
return Integer.MAX_VALUE - 512;
}
}
return Integer.MAX_VALUE - 1024;
}
这个方法就比上个看着简单多了,主要是利用了 ClassUtils.isAssignableValue 方法。参考:ClassUtil
对比权重结果
经过上面的比对得到的 typeDiffWeight 权重和 minTypeDiffWeight 对比。
比 minTypeDiffWeight 小的话那么就是符合的构造函数。记录对应的构造函数及相关参数。否则记录信息到 ambiguousConstructors 中。继续下一个构造函数的对比。
最终对比完毕后,并没有找到合适,那么就要记录相关信息。抛出异常 BeanCreationException 。
使用构造函数实例化
private Object instantiate(
String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {
try {
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName
, this.beanFactory, constructorToUse, argsToUse),
this.beanFactory.getAccessControlContext());
} else {
return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
经过上面复杂的对比过程,终于得到了合适的构造函数、参数类型、参数值,接下来开始实例化对象。
首先获取实例化的策略,一共有三种策略定义在接口 InstantiationStrategy 中:
- 无参构造实例化;
- 指定构造函数实例化;
工厂方法实例化;
它有两个主要的实现类:
来到实例化方法,这里就开始区分来使用不同的实例化策略。
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, Object... args) {
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
return BeanUtils.instantiateClass(ctor, args);
}
else {
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
策略 SimpleInstantiationStrategy
如果 bean 没有 MethodOverrides(没有配置过 lookup-method 或 replaced-method) 那么可以继续处理。继续调用 BeanUtils.instantiateClass(ctor, args),来实例化对象。
org.springframework.beans.BeanUtils#instantiateClasspublic static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
return KotlinDelegate.instantiateClass(ctor, args);
}
else {
Class<?>[] parameterTypes = ctor.getParameterTypes();
Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
Object[] argsWithDefaultValues = new Object[args.length];
for (int i = 0 ; i < args.length; i++) {
if (args[i] == null) {
Class<?> parameterType = parameterTypes[i];
argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
}
else {
argsWithDefaultValues[i] = args[i];
}
}
return ctor.newInstance(argsWithDefaultValues);
}
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
策略 CglibSubclassingInstantiationStrategy
如果 bean 有 MethodOverrides ,那么 SimpleInstantiationStrategy 就处理不了了,需要委托CglibSubclassingInstantiationStrategy 去处理。
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd
, @Nullable String beanName, BeanFactory owner,
@Nullable Constructor<?> ctor, Object... args) {
// Must generate CGLIB subclass...
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.CglibSubclassCreator#instantiate
public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// SPR-10785: set callbacks directly on the instance instead of in the
// enhanced class (via the Enhancer) in order to avoid memory leaks.
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}