Spring 得到候选构造方法之后,如何选择使用哪个构造方法?
ConstructorResolver#autowireConstructor
1、定义三个变量
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
2、explicitArgs 参数代表的是外面getBean传入的参数
AnnotationConfigApplicationContext
context = new AnnotationConfigApplicationContext(MyTest.class);
TestService testService = context.getBean("testService", new UserService(), new UserService());
3、如果传入了 explicitArgs值则构造函数的参数就是用传入的参数
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
4、看一下缓存中是否存在 4.1、如果缓存中存在需要使用的构造方法,且当前构造方法需要的参数已经解析过,取出缓存的构造方法需要的参数列表,如果当前参数列表为null,再判断一下是否有需要解析的参数,如果存在需要解析的参数,需要去解析。
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
4.2、 解析参数 4.2.1、ConstructorResolver#resolvePreparedArguments 得到解析器,如果存在则使用指定的解析器,如果不存在则使用默认的解析器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
4.2.2、遍历所有需要解析的参数数组,判断每个需要解析的参数的类型,执行不同的代码逻辑
if (argValue == autowiredArgumentMarker) {
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter, true);
}
else if (argValue instanceof BeanMetadataElement) {
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
}
else if (argValue instanceof String) {
argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
}
4.2.3、得到对应的参数的参数类型
Class<?> paramType = paramTypes[argIndex];
4.2.4、使用解析器执行解析
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
5、如果没有确定的构造参数或者没有可使用的构造方法参数 5.1、判断是否传入了候选的构造函数数组,如果没有的话,根据类的设置信息来判断获取全部包含私有的构造函数还是只获取公共的构造函数。
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);
}
}
6、如果只有一个候选的构造函数,且没有传入构造参数值,且没有构造参数的时候,(空参构造),直接使用此无参构造
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;
}
}
7、判断当前类需要不需要自动注入 7.1、如果存在候选的构造函数或者BeanDefinition.autowireMode= AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT则为true 8、定义一个参数记录需要使用的构造函数的最小值 8.1、 如果传入的有参数,则设置最小的构造参数个数为 传入的参数个数 8.2、处理BeanDefinition指定参数得到最小的参数个数
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}else {
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
9、对得到的构造函数执行排序
AutowireUtils.sortConstructors(candidates);
10、定义三个变量
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
Deque<UnsatisfiedDependencyException> causes = null;
11、循环当前的所有候选构造函数集合 11.1、 得到当前构造函数的参数个数
int parameterCount = candidate.getParameterCount();
11.2、如果开始循环之前已经得到了可使用的构造函数,且需要使用的参数个数不是null,并且当前构造函数的参数小于 已找到的参数个数,直接结束。
if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
break;
}
11.3、如果当前构造参数个数小于最小的构造函数参数就继续
if (parameterCount < minNrOfArgs) {
continue;
}
例如 下面代码
@Component
public class MyService {
@Autowired(required = false)
public MyService (UserBService userService) {
}
@Autowired(required = false)
public MyService (UserService userService, OrderService orderService) {
}
@Autowired(required = false)
private MyService (OrderService orderService, UserService userService) {
}
}
排序之后的构造函数为
public com.test.MyService (UserService ,OrderService )
public com.test.MyService (OrderService )
private com.test.MyService (OrderService ,UserService )
11.4、得到当前构造参数的类型集合
Class<?>[] paramTypes = candidate.getParameterTypes();
11.5、如果getBean的时候没有传入参数(explicitArgs== null),则 resolvedValues != null 为真 11.5.1、判断当前构造方法上面是否加了@ConstructorProperties注解,获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
11.5.2、如果paramNames == null 获取默认的构造方法的参数名
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
11.5.3、找到这个构造方法需要的参数ConstructorResolver#createArgumentArray
ArgumentsHolder argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
12、如果判断当前类设置的宽松模式,得到一个值,此值越低代表当前构造函数越符合
int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
13、如果已经存在了可使用的构造方法,且本次处理的构造方法得到的 typeDiffWeight == 已存在的构造方法计算出来的值,则添加到 ambiguousConstructors 中 14、如果循环完所有的构造方法,如果没有得到可使用的构造方法,且异常的构造集合不为null,则跑出异常
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)");
}
15、如果已找到了一个可用的构造方法,且存在其他可用的构造方法,且类设置的是严格模式解析,则抛出异常
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)");
}
16、如果getBean没有传入参数,且找到了可用的构造方法参数,则进行缓存
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
17、执行创建
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
|