该篇以createBeanInstance方法为起点分析推断构造方法
怎么一步步到createBeanInstance方法
refresh()-》finishBeanFactoryInitialization-》preInstantiateSingletons-》getBean-》 doGetBean-》createBean-》doCreateBean-》createBeanInstance
推断构造方法是在创建实例化时进行推断的,也就是这个createBeanInstance方法。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 创建一个bean实例(返回一个原始对象)
// Make sure bean class is actually resolved at this point.
// 1. 得到bean的class,并验证class的访问权限是不是public
Class> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 2. 这是Spring提供给开发者的扩展点
// 如果我们要自己来实现创建对象的过程, 那么就可以提供一个Supplier的实现类,
// 当一个BeanDefinition中存在一个Supplier实现类的时候, Spring就利用这个类的get方法来获取实例,
// 而不再走Spring创建对象的逻辑
Supplier> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 3.通过factoryMethod实例化这个bean
// factorMethod这个名称在xml中还是比较常见的, 即通过工厂方法来创建bean对象
// 如果是由@Bean注解创建的bean, 那么该对象就会走instantiateUsingFactoryMethod方法来创建的,而不会走下面的推断构造
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
boolean resolved = false;
boolean autowireNecessary = false;
// 如果在创建bean时没有手动指定构造方法的参数,那么则看当前BeanDefinition是不是已经确定了要使用的构造方法和构造方法参数
// 注意:如果没有手动指定参数,那么就肯定是自动推断出来的,所以一旦发现当前BeanDefinition中已经确定了要使用的构造方法和构造方法参数,
// 那么就要使用autowireConstructor()方法来构造一个bean对象
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 该BeanDefinition是否已经决定了要使用的构造方法或工厂方法
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
// 该BeanDefinition是否已经决定了要使用的构造方法参数
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
// resolved为true,表示当前bean的构造方法已经确定出来了
// autowireNecessary表示当前bean的构造方法的参数已经确定出来了
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 如果构造方法已经确定了,但是没有确定构造方法参数,那就表示没有构造方法参数,用无参的构造方法来实例化bean
return instantiateBean(beanName, mbd);
}
}
// 候选构造器
Constructor>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 通过BeanPostProcessor找出了构造方法
// 或者BeanDefinition的autowire属性为AUTOWIRE_CONSTRUCTOR
// 或者BeanDefinition中指定了构造方法参数值
// 或者在getBean()时指定了args
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 进行构造方法推断并实例化
return autowireConstructor(beanName, mbd, ctors, args);
}
// 没啥用
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 用无参的构造方法来实例化bean
return instantiateBean(beanName, mbd);
}
再看57行这个方法determineConstructorsFromBeanPostProcessors,通过循环最终到了AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors方法
public Constructor>[] determineCandidateConstructors(Class> beanClass, final String beanName)
throws BeanCreationException {
// 在实例化某个对象的过程中会调用这个方法,得到候选构造方法
if (!this.lookupMethodsChecked.contains(beanName)) {
if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
try {
Class> targetClass = beanClass;
do {
// 遍历当前beanClass中所有加了Lookup注解的方法,并且把这些方法的信息封装为LookupOverride对象加载mbd中
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
Assert.state(this.beanFactory != null, "No BeanFactory available");
LookupOverride override = new LookupOverride(method, lookup.value());
try {
RootBeanDefinition mbd = (RootBeanDefinition)
this.beanFactory.getMergedBeanDefinition(beanName);
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(beanName,
"Cannot apply @Lookup to beans without corresponding bean definition");
}
}
});
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
}
}
// lookupMethodsChecked是一个set,用来记录哪些bean的@lookup注解被解析了,下一次就不用解析了
this.lookupMethodsChecked.add(beanName);
}
// 先检查candidateConstructorsCache中是否缓存了当前bean中可用的构造方法
Constructor>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
// 如果没有筛选过构造方法,就开始筛选
if (candidateConstructors == null) {
Constructor>[] rawCandidates;
try {
// 拿到当前类所有的构造方法,如果没有写任何构造方法,这里会返回一个无参的构造方法
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
// candidates 就是用来存储所有被筛选出来的构造方法,其实可以认为, 就是把所有@Autowired注解标注的方法放到里面,
// 但是还多放了一个默认构造方法
List> candidates = new ArrayList<>(rawCandidates.length);
// requiredConstructor表示@Autowired标注并且required为true的构造方法, 因为只允许出现一个这样的构造方法,
//所以当这个变量存在值后, 又出现了一个相同情况的构造方法的话, Spring就会抛出一个错误
Constructor> requiredConstructor = null;
// defaultConstructor用来保存默认构造方法
Constructor> defaultConstructor = null;
// 如果是kotlin的类才起效,如果是java中的类则直接返回null
Constructor> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
// 遍历所有的构造方法
for (Constructor> candidate : rawCandidates) {
// nonSyntheticConstructors这个变量是和primaryConstructor != null一起使用的,所以也不用管
if (!candidate.isSynthetic()) {
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}
// 查看该构造方法上是否存在@Autowired注解,或者看代理类的父类中对应的构造方法上是否存在@Autowired注解
MergedAnnotation> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
// 如果当前类是cglib生成的代理类,则获取期父类
Class> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
Constructor> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
// Simply proceed, no equivalent superclass constructor found...
}
}
}
// 如果构造方法上存在@Autowired注解
if (ann != null) {
// requiredConstructor表示程序员手动指明的要使用的哪个构造方法
// 所以如果有多个构造方法上都写了@Autowired注解就会报错,required位true的情况下
// 因为作为程序员你如果告诉Spring多个构造方法,那Spring也就不知道到底要使用哪一个了
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
// 查看@Autowired的required属性值,默认位true
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
requiredConstructor = candidate;
}
// candidates中存的是加了@Autowired注解的构造方法
candidates.add(candidate);
}
// 如果当前构造方法上不存在@Autowired,并且是无参构造方法,则记录一下该无参构造方法
// 所以我们可以方法,在遍历构造方法时,其实只关心无参构造方法和加了@Autowired注解的构造方法
else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}
}
// 如果存在添加了@Autowired的构造方法
if (!candidates.isEmpty()) {
// 分为两种请求,要么candidates中包含一个required等于true的构造方法
// 要么candidates中包含一个或多个required等于false的构造方法
// 如果没有指定required为true的构造方法,那么就把构造方法添加到candidates中去,后续一起进行推断
if (requiredConstructor == null) {
if (defaultConstructor != null) {
// 那么就把无参的构造方法也添加进去
candidates.add(defaultConstructor);
}
// 如果没有指定required为true的构造方法,并且也没有无参的构造方法,并且只有一个构造方法
else if (candidates.size() == 1 && logger.isInfoEnabled()) {
// 给一个提示,没有无参的构造方法,然后又只有一个@Autowired(required=false)的构造方法
// 所以其实一定会用这个构造方法,所以打印一个日志,告诉程序员,你其实可以把required改为true
logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
"': single autowire-marked constructor flagged as optional - " +
"this constructor is effectively required since there is no " +
"default constructor to fall back to: " + candidates.get(0));
}
}
// candidateConstructors就是当前方法的返回值
// 把candidates方法,两种情况,要么只有一个@Autowired(required=true)的构造方法,要么多个@Autowired(required=false)+一个无参构造方法
candidateConstructors = candidates.toArray(new Constructor>[0]);
}
// 没有加了@Autowired注解的构造方法,那么则判断是不是只有一个有参的构造方法,如果是则返回
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor>[] {rawCandidates[0]};
}
// primaryConstructor != null 不管
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor>[] {primaryConstructor, defaultConstructor};
}
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor>[] {primaryConstructor};
}
// 如果没有构造方法上添加了@Autowired注解,并且有多个构造方法,并且没有primaryConstructor
else {
// 返回一个空的Constructor数组,表示没有推断出来构造方法
candidateConstructors = new Constructor>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
// 要么返回一个required=true的构造方法
// 要么返回多个requreid=false+无参的构造方法
// 要么返回唯一的一个有参的构造方法
// 如果只有一个无参的构造方法,这里会返回null,外层逻辑会默认使用无参构造方法进行实例化
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
该方法作用为获取到构造器的候选者,该方法最终返回的内容可能有以下几种:
1. 返回一个@Autowired required=true的构造方法
2. 返回多个@Autowired requreid=false和一个没被@Autowired的无参的构造方法
3. 返回唯一的一个有参的构造方法
4. 如果只有一个无参的构造方法,这里会返回null,外层逻辑会默认使用无参构造方法进行实例化
这个方法的主要逻辑如下:
获取到构造器候选者后进入这块逻辑:
// 通过BeanPostProcessor找出了构造方法
// 或者BeanDefinition的autowire属性为AUTOWIRE_CONSTRUCTOR
// 或者BeanDefinition中指定了构造方法参数值
// 或者在getBean()时指定了args
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 进行构造方法推断并实例化
return autowireConstructor(beanName, mbd, ctors, args);
}
我们进入autowireConstructor推断构造方法中查看。
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor>[] chosenCtors, @Nullable Object[] explicitArgs) {
// mbd当前bean的BeanDefinition
// chosenCtors构造方法
// explicitArgs,getBean()方法中所传递的参数
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 是否通过getBean()方法指定了构造方法参数值
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 从缓存中获取构造方法和构造方法参数值
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor>) mbd.resolvedConstructorOrFactoryMethod;
// 找到了mbd中缓存的构造方法
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果存在构造方法参数值,那么则对参数值进行类型转化
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 如果待使用的构造方法为null,或待使用的构造方法参数为null
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// chosenCtors表示所指定的构造方法,没有指定则获取beanClass中的所有的构造方法作为候选者,从这些构造方法中选择一个构造方法
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;
}
}
// 如果指定了多个构造方法,或者autowireMode是构造方法自动注入,则要自动选择构造方法
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null; // 记录解析后的构造方法参数值
int minNrOfArgs; // 表示所有构造方法中,参数个数最少的构造方法的参数个数是多少
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 从BeanDefinition中获取所设置的构造方法参数值
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 记录解析后的构造方法参数值
resolvedValues = new ConstructorArgumentValues();
// 解析BeanDefinition中所设置的构造方法参数值(index跳跃)
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 按构造方法的参数个数降序排序,参数个数多的在前
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set> ambiguousConstructors = null;
LinkedList causes = null;
// 遍历构造方法,找到一个最合适的(贪婪)
// 先看参数列表最长的构造方法,根据每个参数的参数类型和参数名去找bean
for (Constructor> candidate : candidates) {
// 当前构造方法的参数个数
int parameterCount = candidate.getParameterCount();
// 已经找到了一个带使用的构造方法已经参数,并且该参数个数大于当前遍历的,则不用继续遍历了
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();
// 没有通过getBean()方法指定构造方法参数值
if (resolvedValues != null) {
try {
// 获取参数名
// 查看是否在构造方法上使用@ConstructorProperties注解来定义构造方法参数的名字
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
// 根据当前构造方法的参数类型和参数名从beanFactory中得到bean作为参数值
// resolvedValues表示所指定的构造方法参数值
// paramTypes,当前构造方法的参数类型列表
// paramNames,当前构造方法的参数值列表
// getUserDeclaredConstructor(candidate)获取父类中被重写的构造方法
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
// 如果找不到对应的bean,也不会直接报错,只能证明当前遍历到的构造方法不能用
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 {
// 通过getBean()方法指定了构造方法参数值
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
// 如果参数个数匹配,则把所有参数值封装为一个ArgumentsHolder对象
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 执行到这里,表示当前构造方法可用,并且也找到了对应的构造方法参数值
// 但是还需要判断,当前构造方法是不是最合适的,也许还有另外的构造方法更合适
// 根据参数类型和参数值计算权重
// Lenient宽松,默认宽松模式是开启的
// 在宽松模式下,会判断每个参数值的类型和当前构造方法的参数类型的距离
// 在非宽松模式下,会忽略每个参数值的类型和当前构造方法的参数类型的距离,只要是父子关系距离是一样的
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) {
// 如果权重一样,则记录在ambiguousConstructors中,继续遍历下一个构造方法
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 " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
// 如果存在权重一样的构造方法并且不是宽松模式,也报错,因为权重一样,Spring不知道该用哪个
// 如果是宽松模式则不会报错,Spring会用找到的第一个
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
// 如果不是通过getBean()方法指定的参数,那么就把找到的构造方法参数进行缓存
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;
}
推断构造方法流程图如下:
总结一下推断构造:
1.如果bd使用Supplier接口或者是@Bean方式获取bean,那么就不进行推断方法,直接返回实例。
2.确定构造方法是否已经确认推断出来了,推断出就直接使用推断出的构造器进行实例化,如果没有推断出则继续。
3.进行构造器选举,选出符合的构造器。
4.进行推断构造,如果构造方法和参数都确定则进行实例化,不符合则对候选构造器进行处理。
5.根据参数类型和参数值计算权重,选择最合适的构造器返回,完成实例化。