这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
【1】autowireConstructor
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
前面的就只是一个构造方法,重要的是下面的:
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
//ctors:从这些方法中取一个来
//args:getBean中,手动传的参数
@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) {
//如果args指定了,那么直接用这些指定的参数来构造
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) {
//和RuntimeBeanReference有关,这里在后面回去解析[T(1)]
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
//上面[T(1)]的地方就会在这里来解析
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
//两个至少有一个未知,也就是说:此时还没有办法来构造类示例
if (constructorToUse == null || argsToUse == null) {
Constructor<?>[] candidates = chosenCtors;
//如果之前没有给到构造方法
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
//根据bd的配置,来决定取public的构造方法,或所有构造方法
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);
}
}
//如果只有一个构造方法可以选用,且没有手动指定参数,且BD里也没有传值
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;
}
}
//有若干个构造方法,往下需要从这里面选1个来构造示例
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
//这个变量,指的是参数个数如果比这个数少,那么就不会用来构造示例
int minNrOfArgs;
//这里的参数就是前面手动getBean时传进来的
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
//这里指的是通过BD,来手动指定的参数的个数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
//这里会排序,排序规则是:优先public,随后参数个数倒序
AutowireUtils.sortConstructors(candidates);
//这个参数,指的是构造方法的得分:因为即使我们确定了某个构造方法,但可能参数个数是一样的,我们需要根据某些方式,去确认具体选择哪一个
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
Deque<UnsatisfiedDependencyException> causes = null;
//遍历上面排序的构造方法
for (Constructor<?> candidate : candidates) {
int parameterCount = candidate.getParameterCount();
//这里已经选了某个构造方法,然后当前的构造方法,参数个数小于minNrOfArgs,那么就没必要再查看了,直接返回
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;
}
//这里还没选选某个构造方法,参数个数小于minNrOfArgs:此时要考虑private的构造方法,因此需要继续
if (parameterCount < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
Class<?>[] paramTypes = candidate.getParameterTypes();
if (resolvedValues != null) {
try {
//取参数名称【1.1】
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
//获取代码中参数的名称
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
//这里就是根据参数类型、名称,找对应的bean对象【1.2】
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 ArrayDeque<>(1);
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
//看,这里就会来计算得分,来确认构造方法【1.3】
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);
}
}
//这里指的就是:最终没有找到合适的构造方法
//为什么?可能是某个参数找bean并没有找到(例如:根据类找找到多个,然后根据名字找,但名字找不到),在前面会存起来
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)");
}
//有多个分数相同的构造方法,且mbd不是宽松模式,那么就会报错
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);
}
}
//这里就会构造bean示例
Assert.state(argsToUse != null, "Unresolved constructor arguments");
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
【1.1】构造方法@ConstructorProperties
可以在构造方法上,通过该注解来指定参数别名:
@ConstructorProperties({"1","2","3",...})
【1.2】 createArgumentArray
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//遍历构造方法的参数类型
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
//看参数类型和名称
Class<?> paramType = paramTypes[paramIndex];
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// If we couldn't find a direct match and are not supposed to autowire,
// let's try the next generic, untyped argument value as fallback:
// it could match after type conversion (for example, String -> int).
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
if (valueHolder != null) {
// We found a potential match - let's give it a try.
// Do not consider the same value definition multiple times!
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
try {
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
}
catch (TypeMismatchException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Could not convert argument value of type [" +
ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
}
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// No explicit match found: we're either supposed to autowire or
// have to fail creating an argument array for the given constructor.
if (!autowiring) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
"Ambiguous argument values for parameter of type [" + paramType.getName() +
"] - did you specify the correct bean references as arguments?");
}
try {
//如果某个参数没指定,且autowired为true
//这里会调用依赖注入里面的resolveDependency方法:根据类型再名字,来从容器里找bean对象尝试赋值
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
//存起来,给外面构造方法来使用
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
【1.3】分数计算
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
可以看到这里还是分为宽松模式和非宽松模式的:
宽松模式:
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.
//这里:arguments代表找到并转换后的arguments;rawArguments指:找到的arguments
int typeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.arguments);
int rawTypeDiffWeight = MethodInvoker.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;
return Math.min(rawTypeDiffWeight, typeDiffWeight);
}
而计算的在这里:
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])) {
return Integer.MAX_VALUE;
}
if (args[i] != null) {
//看这里:如果有继承,每个继承差2分,直到继承类和参数指定类相同
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;
}
严格模式:
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;
}
严格模式就少了很多判断了,而且只有三种返回值,在这种情况下,就更可能出现最佳冲突的情况。