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从这些构造方法中去自动选择一个构造方法。

 

 

源码

 

 

 

AnnotationConfigApplicationContext(); --->refresh();-->finishBeanFactoryInitialization(beanFactory)完成beanFactory的初始化(实例化非懒加载的单例bean)
;-->beanFactory.preInstantiateSingletons(); 实例化所有非懒加载的bean -->getBean(beanName);-->doGetBean(name, null, null, false);-->createBean(beanName, mbd, args);-->doCreateBean(beanName, mbdToUse, args);-->createBeanInstance(beanName, mbd, args);

 

其中getBean()时指定了args 就举例说明如下:

spring 推断构造方法_第1张图片

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

// Candidate constructors for autowiring?
		Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

// 通过BeanPostProcessor找出了构造方法
// 或者BeanDefinition的autowire属性为AUTOWIRE_CONSTRUCTOR  就是xml里面配置的
// 或者BeanDefinition中指定了构造方法参数值   如xml中的那种
// 或者在getBean()时指定了args
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 进行构造方法推断并实例化
			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);
	}

 

其中

spring 推断构造方法_第2张图片

 

就是指的user参数

 

 

 

 

 

  • AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean实例
  • 根据BeanDefinition加载类得到Class对象
  • 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返回
  • 如果BeanDefinition中存在factoryMethodName,那么就调用该工厂方法得到一个bean对象并返回
  • 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
  • 调用SmartInstantiationAwareBeanPostProcessor的determineCandidateConstructors()方法得到哪些构造方法是可以用的
  • 如果存在可用得构造方法,或者当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean的时候指定了构造方法参数值,那么就调用autowireConstructor()方法自动构造一个对象
  • 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象

 

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

注意其中这样的一行代码Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);示例如下

  直接是使用@Autowired注解的构造方法

spring 推断构造方法_第3张图片

 

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

AutowiredAnnotationBeanPostProcessor的determineCandidateConstructors方法
	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> 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()) {
									//说明存在多个@Autowired的构造方法并且存在@Autowired(required = true)的情况
									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的构造方法

// 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]);
					}
// 没有加了@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);
	}

å¨è¿éæå¥å¾çæè¿°

 

针对上面的方法举例说明

 

spring 推断构造方法_第4张图片

 

报错原因  因为遍历@Autowired的构造方法的时候

spring 推断构造方法_第5张图片

 

 

调换换下顺序

spring 推断构造方法_第6张图片

 

下面这边报错

spring 推断构造方法_第7张图片

 

 

也就是说一个类有了一个@autowried(true)的构造方法就不能有别的@autowried的构造方法 除非@autowried的构造方法都为false

 

 

下面这样的多个构造方法但是木有@autowried的构造方法那么就用无参的构造方法去兜底

此时determineConstructorsFromBeanPostProcessors 返回null

spring 推断构造方法_第8张图片

 

 


 

下面看autowireConstructor(beanName, mbd, ctors, args);

其中

定义bd的时候指定参数值 mbd.hasConstructorArgumentValues() 就是中间的con标签

下图表示构造方法参数至少要有两个

spring 推断构造方法_第9张图片

 

 


 

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

			// 有了构造方法之后,则进行自动推断

			// 如果只有一个构造方法(candidates.length == 1),并且没有指定构造方法参数值(explicitArgs == null),则需要判断是不是无参构造方法(mbd.hasConstructorArgumentValues()),如果是则可以使用无参构造方法进行实例化
			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是构造方法自动注入(xml写法那种),则要自动选择构造方法
			// 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();

				// 已经找到了一个带使用的构造方法已经参数,并且该参数个数大于当
				// 前遍历的,则不用继续遍历了 (因为 循环的集合是 按照参数个数降序排序过的 ,spring默认找的是参数最多的构造方法)
				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宽松,默认宽松模式是开启的
				// 在宽松模式下,会判断每个参数值的类型和当前构造方法的参数类型的距离
				// 在非宽松模式下,会忽略每个参数值的类型和当前构造方法的参数类型的距离,只要是父子关系距离是一样的 即 userInterface 到 user  和  user 到user 的距离认为是一样的 
				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;
	}

 

 

其中 权重 分为宽松和非宽松模式

先说宽松模式

举例如下:

spring 推断构造方法_第10张图片

spring 推断构造方法_第11张图片

 

假设 User实现了 UserInterface   那么 第一个方法权重是1  第二个是0  因为第二个参数值的类型更适合匹配 那么第二个构造方法就匹配

 

第一个方法 第三个参数的类型UserInterface 和实际类型  user 的距离 为1

第二个方法 第三个参数 user类型和 实际类型 user类型一致   user的距离  为 0 

权重越小 越匹配

 

其中

// 在非宽松模式下,会忽略每个参数值的类型和当前构造方法的参数类型的距离,只要是父子关系距离是一样的 即 userInterface 到 user  和  user 到user 的距离认为是一样的 

spring 推断构造方法_第12张图片

那么这种情况下 算的权重分就是一样的  就会报错 因为找不到合适的构造方法

 

 

下面来说下怎么算分的

为什么分越少优先级越高?

 

主要是计算找到的bean和构造方法参数类型匹配程度有多高。

 

假设bean的类型为A,A的父类是B,B的父类是C,同时A实现了接口D

如果构造方法的参数类型为A,那么完全匹配,得分为0

如果构造方法的参数类型为B,那么得分为2

如果构造方法的参数类型为C,那么得分为4

如果构造方法的参数类型为D,那么得分为1

 

可以直接使用如下代码进行测试:

Object[] objects = new Object[]{new A()};

// 0
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{A.class}, objects));

// 2
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{B.class}, objects));

// 4
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{C.class}, objects));

// 1
System.out.println(MethodInvoker.getTypeDifferenceWeight(new Class[]{D.class}, objects));

所以,我们可以发现,越匹配分数越低。

可以发现只要是父子继承关系 就一直结果+2  接口是+1

	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) {
				// 当前参数类型
				Class paramType = paramTypes[i];
				// 对应的参数值的父类   user---superClass
				Class superClass = args[i].getClass().getSuperclass();
				// 遍历父类
				while (superClass != null) {
					// 如果某个父类等于参数类型则解释,result+2
					if (paramType.equals(superClass)) {
						result = result + 2;
						superClass = null;
					}
					// 如果paramType是superClass子类,那么result+2,继续找父类,所以层级越多result越大
					else if (ClassUtils.isAssignable(paramType, superClass)) {
						result = result + 2;
						superClass = superClass.getSuperclass();
					}
					else {
						superClass = null;
					}
				}
				// 遍历完父类之后,如果参数类型是一个接口,则result+1
				if (paramType.isInterface()) {
					result = result + 1;
				}
			}
		}
		// 最后得出一个分数
		return result;
	}

 

 

 

 

 

 

 

 

  1. 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
  2. 如果没有确定的构造方法或构造方法参数值,那么
    1. 如果没有确定的构造方法,那么则找出类中所有的构造方法
    2. 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化
    3. 如果有多个可用的构造方法或者当前Bean需要自动通过构造方法注入
    4. 根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
    5. 对所有的构造方法进行排序,参数个数多的在前面
    6. 遍历每个构造方法
    7. 如果不是调用getBean方法时所指定的构造方法参数值,那么则根据构造方法参数类型找值
    8. 如果时调用getBean方法时所指定的构造方法参数值,就直接利用这些值
    9. 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的

 

spring 推断构造方法_第13张图片

 

 

 

 


 

 

 

 

 

 

 

 

 

 


 


 


 

你可能感兴趣的:(spring 推断构造方法)