Spring源码解析——推断构造方法的底层原理分析

概述

Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。
一般情况下,一个类只有一个构造方法:

  1. 要么是无参的构造方法
  2. 要么是有参的构造方法

如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。

如果只有一个有参的构造方法,那么实例化时能使用这个构造方法吗?要分情况讨论:

  1. 使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,那么Spring会根据构造方法的参数信息去寻找bean,然后传给构造方法
  2. 使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为构造方法参数值。

上面是只有一个构造方法的情况,那么如果有多个构造方法呢?

又分为两种情况,多个构造方法中存不存在无参的构造方法。
分析:一个类存在多个构造方法,那么Spring进行实例化之前,该如何去确定到底用哪个构造方法呢?

  1. 如果开发者指定了想要使用的构造方法,那么就用这个构造方法
  2. 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法
  3. 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构造方法,则报错

针对第一点,开发者可以通过什么方式来指定使用哪个构造方法呢?

  1. xml中的标签,这个标签表示构造方法参数,所以可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法
  2. 通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值

再来看第二点,如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法,对于这一点,只能用在ClassPathXmlApplicationContext,因为通过AnnotationConfigApplicationContext没有办法去指定某个bean可以自动去选择构造方法,而通过ClassPathXmlApplicationContext可以在xml中指定某个bean的autowire为constructor,虽然这个属性表示通过构造方法自动注入,所以需要自动的去选择一个构造方法进行自动注入,因为是构造方法,所以顺便是进行实例化。

当然,还有一种情况,就是多个构造方法上写了@Autowired注解,那么此时Spring会报错。但是,因为@Autowired还有一个属性required,默认为ture,所以一个类中,只有能一个构造方法标注了@Autowired或@Autowired(required=true),有多个会报错。但是可以有多个@Autowired(required=false),这种情况下,需要Spring从这些构造方法中去自动选择一个构造方法。

源码

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);
		}

		// Shortcut when re-creating the same bean...
		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表示该BeanDefinition是否已经决定了要使用的构造方法参数
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			} else {
				// 如果构造方法已经确定了,但是没有确定构造方法参数,那就表示没有构造方法参数,用无参的构造方法来实例化bean
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
//		 一个类有多个构造方法,那么到底哪些构造方法是可以拿来用的,Spring也提供了一个扩展点,程序员可以进行控制
//		 利用beanPostProcessor来选取构造方法,如果返回值(ctors)不为空,则表示利用beanPostProcessor找到了候选的构造方法,那么则进行自动推断
//		 如果当前bd是构造方法自动注入,那么也进行自动推断
//		 如果当前bd中存在了构造方法参数值,那么也进行自动推断
//		 如果是在getBean时指定了args, 那么也进行自动推断
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// 从ctors中自动选择一个构造方法
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		// 没啥用
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		// 用无参的构造方法来实例化bean
		return instantiateBean(beanName, mbd);
	}
  1. AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean实例
  2. 根据BeanDefinition加载类得到Class对象
  3. 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返回
  4. 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个bean对象并返回
  5. 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
  6. 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法得到哪些构造方法是可以用的
  7. 如果存在可用得构造方法,或者当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean的时候指定了构造方法参数值,那么就调用autowireConstructor()方法自动构造一个对象
  8. 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象

利用beanPostProcessor来选取构造方法,如果返回值(ctors)不为空,则表示利用beanPostProcessor找到了候选的构造方法,那么则进行自动推断

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
			throws BeanCreationException {
		// 在实例化某个对象的过程中会调用这个方法,得到候选构造方法

		// Let's check for lookup methods here...
		if (!this.lookupMethodsChecked.contains(beanName)) {
			// @Lookup注解的使用 https://www.jianshu.com/p/fc574881e3a2
			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);
		}

		// Quick check on the concurrent map first, with minimal locking.
		// 先检查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<Constructor<?>> 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()) {
						// Add default constructor to list of optional constructors, as fallback.
						// 如果没有指定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]);
					}
					// 如果candidates为空,表示没有构造方法上添加了@Autowired注解,并且只有一个构造方法,并且该构造方法的参数个数大于0
					// 那么表示只有一个构造方法可用,直接方法
					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);
				}
			}
		}

		// 总结一下determineCandidateConstructors这个方法到底在做什么?
		// 首先,这个方法是BeanPostProcessor中的逻辑,所以它是一个插件,可有可无,比如现在这个类叫做AutowiredAnnotationBeanPostProcessor
		// 那么很明显,这个是处理@Autowired注解的,所以我们可以理解为这个方法是在处理构造方法上的@Autowired注解
		// 如果这么理解的话,可以看出来,这个方法主要作用并不是“推断”,因为我们所理解的推断是“推理决断”,从多个选择一个
		// 所以我们就可以把当前这个方法里面处理构造方法上的Autowired
		// 那么这个方法的功能,我们就好理解了:
		// 1. 只能有一个@Autowired(required=true)的构造方法,有多个会报错,如果是这种情况,那么就应该这个构造方法来实例化对象
		// 2. 可以有多个@Autowired(required=false)的构造方法,如果是这种情况,那么还不确定到底应该用哪个构造方法来实例化对象,
		// 所以,如果是这种情况,我们还需要把无参构造方法加到candidateConstructors集合中,一起作为候选构造方法
		// 3. 如果没有@Autowired的构造方法,但是如果本来只有一个有参构造方法,则也表明了只有这个构造方法可用
		// 4. 如果没有@Autowired的构造方法,并且有多个构造方法,则返回空

		// 再总结一下,这个方法做一件事情,就是去找到,到底哪些构造方法是可用的
		// 1. 程序员通过@Autowired注解指定的构造方法
		// 2. 在没有指定时,如果这个类只有一个构造方法,那么就应该用这个构造方法
		// 3. 否则,当前方法也不知道应该用哪个构造方法
		return (candidateConstructors.length > 0 ? candidateConstructors : null);
	}

Spring源码解析——推断构造方法的底层原理分析_第1张图片
从ctors中自动选择一个构造方法

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;

		// 得到构造方法的参数,
		if (explicitArgs != null) {
			// getBean()时传递了args参数时才进这里
			argsToUse = explicitArgs;
		}
		else {
			// 查看BeanDefinition中是否已经确定出来了所要使用的构造方法和构造方法的参数值(起到缓存的作用)
			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) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}

		// 如果BeanDefinition中没有缓存应该使用的构造方法,或者缓存了构造方法但是没有缓存应该使用的构造方法参数值
		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];
				// 并且是无参的构造方法,则可以直接使用该无参构造方法进行实例化了
				// 同时把该构造方法缓存到BeanDefinition中
				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; // 表示最少的构造方法的参数个数,要么是用户指定的构造方法参数,要么是BeanDefinition中所指定的
							 // 表示在选择构造方法时,选到的构造方法参数至少要能用上这些参数
			if (explicitArgs != null) {
				minNrOfArgs = explicitArgs.length;
			}
			else {
				// 从BeanDefinition中获取所设置的构造方法参数值
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				// 记录解析后的构造方法参数值
				resolvedValues = new ConstructorArgumentValues();
				// 解析BeanDefinition中所设置的构造方法参数值
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}

			// 按构造方法的参数个数的多少降序排序,参数个数多的在前
			AutowireUtils.sortConstructors(candidates);

			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			// 遍历构造方法,找到一个最合适的(贪婪)
			// 先看参数列表最长的构造方法,根据每个参数的参数类型和参数名去找bean
			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;
				}
				// 如果构造方法参数小于minNrOfArgs,
				if (parameterCount < minNrOfArgs) {
					continue;
				}

				// 到这里,要么还没确定构造方法的参数值, constructorToUse或argsToUse等于空
				// 要么已经确定了一个构造方法, constructorToUse和argsToUse不等于null,但是当前遍历到的构造方法的参数个数和argsToUse相等

				// 检查当前遍历的构造方法是否适合
				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 {
					// Explicit arguments given -> arguments length must match exactly.
					// 如果getBean提供的参数个数不等于当前构造方法的参数个数,则当前构造方法不合适
					if (parameterCount != explicitArgs.length) {
						continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}

				// 确定了当前构造方法的参数值之后,目的是需要记录一下constructorToUse
				// 这里还需要判断一下,因为可能存在两个构造方法都能符合上面的逻辑,那么到底用哪一个呢?

				// 根据参数类型计算权重
				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);
			}

			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. 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
  2. 如果没有确定的构造方法或构造方法参数值,那么
    a. 如果没有确定的构造方法,那么则找出类中所有的构造方法
    b. 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
    c. 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
    d. 根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
    e. 对所有的构造方法进行排序,参数个数多的在前面
    f. 遍历每个构造方法
    g. 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
    h. 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
    i. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的
    Spring源码解析——推断构造方法的底层原理分析_第2张图片

你可能感兴趣的:(Spring)