spring-ioc-推断构造函数-手动装配



 

耀眼的星星并不是最高的

此篇文章我们来介绍spring ioc的精髓之一,如何推断构造函数,分为手动装配和自动装配两部分进入源码。

我们知道spring bean的生命周期中是先初始化对象再来装配属性,那么我们就从上文的构造方法循环依赖返回的对象作为入口。

本次的测试环境为

package org.springframework.waf.entity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestBo {

	public TestBo(){System.out.println("default");}//默认的

	public TestBo(IMenu iMenu){System.out.println("IMenu");}//接口作为一个参数

	public TestBo(MenuImpl menu){System.out.println("MenuImpl");}//实现类作为一个参数

	public TestBo(IMenu iMenu,MenuImpl menu){System.out.println("IMenu MenuImpl");}//接口+实现类

	public TestBo(IMenu iMenu,MenuImpl menu,PersonBo personBo){//接口+实现类+父类
		System.out.println("IMenu MenuImpl PersonBo");}

	public TestBo(IMenu iMenu,MenuImpl menu,PersonBo personBo,UserBo userBo){//接口+实现类+父类+子类
		System.out.println("IMenu MenuImpl PersonBo UserBo");}

	public TestBo(IMenu iMenu,MenuImpl menu,PersonBo personBo,UserBo userBo,String str){
		System.out.println("IMenu MenuImpl PersonBo UserBo str");}//接口+实现类+父类+子类+String类

	private TestBo(PersonBo personBo,UserBo userBo){//私有的父类+子类
		System.out.println("private PersonBo UserBo");}
}



package org.springframework.waf;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.waf.appconfig.AppConfig;

public class TestMain {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
	}
}

自动装配的环境添加

package org.springframework.waf.processor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("testBo");
		beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
	}
}

我们通过上面的断点会进入到以下的方法(上半部分)

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

	/**
	 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
	 * 使用适当的实例化策略为指定的bean创建一个新实例:
	 * factory method, constructor autowiring, or simple instantiation.
	 * 工厂方法,构造函数自动装配,或简单实例化。
	 * @param beanName the name of the bean
	 * @param mbd the bean definition for the bean bean的定义(BeanDefinition)
	 * @param args explicit arguments to use for constructor or factory method invocation 参数是构造函数或工厂方法调用的显式参数
	 * @return a BeanWrapper for the new instance 返回新实例的BeanWrapper
	 * @see #obtainFromSupplier
	 * @see #instantiateUsingFactoryMethod
	 * @see #autowireConstructor
	 * @see #instantiateBean
	 */
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		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());}
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//除去上面的一些校验之后
		if (mbd.getFactoryMethodName() != null) {//我们的对象没有使用工厂方法来创建(xml bean标签属性 factory-method属性,具体可参考官网)
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
		// Shortcut when re-creating the same bean...
		// if (mbd.resolvedConstructorOrFactoryMethod != null) {
		// 这行代码可以解释为 解析过构造方法或者工厂方法的 BeanDefinition
		// 这部分代码暂时能能想到的就是原型对象 @Scope("prototype")
		// 在我们第二次 ac.getBean("beanName") 的时候会进行第二次初始化这个对象(不是指 BeanDefinition )
		// 那么第一次肯定已经解析过了,所以说现在测试环境中的单例对象 beanName = testBo 是不会进入这段代码的
		// 我们改成 @Scope("prototype") 来看一看
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

先使用单例测试一次

我们再改成原型对象@Scope("prototype") ,spring原型对象的初始化和单例的不一样,需要在getBean的时候才会进行初始化

package org.springframework.waf;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.waf.appconfig.AppConfig;

public class TestMain {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
		ac.getBean("testBo");//第一次断点
		ac.getBean("testBo");//第二次断点
	}
}

第一次应该会和上面图中的结果一样

跑完进入下一次断点

这段代码我们先到这个地方,因为下面的单例选择构造方法也会有相同的调用链,改回来再看这个方法的下半部分

		// Candidate constructors for autowiring?
		// 通过第一次判断返回合适的构造方法
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		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.
		return instantiateBean(beanName, mbd);
	}

我们进入第一行代码看看spring到底是如何选择一个合适的构造方法的(我们现在的实体类中一共有8个构造方法)

	protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
			throws BeansException {

		if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {//hasInstantiationAwareBeanPostProcessors() 默认为true
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				/** getBeanPostProcessors()
				 *  0 = {ApplicationContextAwareProcessor@2313}
				 *  1 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@2323} 返回空了
				 *  2 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@2324}
				 *  3 = {CommonAnnotationBeanPostProcessor@2325}
				 *  4 = {AutowiredAnnotationBeanPostProcessor@2326} 最终正真处理逻辑的是这个 处理器
				 *  5 = {ApplicationListenerDetector@2327}
				 */
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					// SmartInstantiationAwareBeanPostProcessor super class --> BeanPostProcessor
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
					if (ctors != null) {
						return ctors;
					}
				}
			}
		}
		return null;
	}

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors 

	public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
			throws BeanCreationException {

		// Let's check for lookup methods here..
		// @lookup 可以参照官网解释及用途
		if (!this.lookupMethodsChecked.contains(beanName)) {
			try {
				ReflectionUtils.doWithMethods(beanClass, 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");
						}
					}
				});
			}
			catch (IllegalStateException ex) {
				throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
			}
			this.lookupMethodsChecked.add(beanName);
		}

		// Quick check on the concurrent map first, with minimal locking.
		// candidateConstructors 为已经解析过的类选中后的构造方法的集合,下面选择出来的会放进这个集合中
		// 这一段 如果 是单例的@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();
						/**
						 * 0 = {Constructor@2506} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.IMenu,org.springframework.waf.entity.MenuImpl,org.springframework.waf.entity.PersonBo)"
						 * 1 = {Constructor@2507} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.IMenu,org.springframework.waf.entity.MenuImpl,org.springframework.waf.entity.PersonBo,org.springframework.waf.entity.UserBo)"
						 * 2 = {Constructor@2508} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.IMenu,org.springframework.waf.entity.MenuImpl,org.springframework.waf.entity.PersonBo,org.springframework.waf.entity.UserBo,java.lang.String)"
						 * 3 = {Constructor@2509} "private org.springframework.waf.entity.TestBo(org.springframework.waf.entity.PersonBo,org.springframework.waf.entity.UserBo)"
						 * 4 = {Constructor@2510} "public org.springframework.waf.entity.TestBo()"
						 * 5 = {Constructor@2511} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.IMenu)"
						 * 6 = {Constructor@2512} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.MenuImpl)"
						 * 7 = {Constructor@2513} "public org.springframework.waf.entity.TestBo(org.springframework.waf.entity.IMenu,org.springframework.waf.entity.MenuImpl)"
						 */
					}
					catch (Throwable ex) {
						throw new BeanCreationException(beanName,
								"Resolution of declared constructors on bean Class [" + beanClass.getName() +
								"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
					}
					List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
					Constructor<?> requiredConstructor = null;
					Constructor<?> defaultConstructor = null;
					Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
					int nonSyntheticConstructors = 0;
					for (Constructor<?> candidate : rawCandidates) {
						if (!candidate.isSynthetic()) {
							nonSyntheticConstructors++;
						}
						else if (primaryConstructor != null) {
							continue;
						}
						// 去找有没有去指定使用哪一个构造方法 即 加 @Autowired 注解
						AnnotationAttributes ann = findAutowiredAnnotation(candidate);
						if (ann == null) {
							Class<?> userClass = ClassUtils.getUserClass(beanClass);
							// 讲道理 userClass == beanClass 所以不会进 如果是 factorybean 呢?不知道会不会进
							if (userClass != beanClass) {
								try {
									Constructor<?> superCtor =
											userClass.getDeclaredConstructor(candidate.getParameterTypes());
									ann = findAutowiredAnnotation(superCtor);
								}
								catch (NoSuchMethodException ex) {
									// Simply proceed, no equivalent superclass constructor found...
								}
							}
						}
						if (ann != null) {
							if (requiredConstructor != null) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}
							boolean required = determineRequiredStatus(ann);//默认为 true
							if (required) {
								if (!candidates.isEmpty()) {
									throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
								}
								requiredConstructor = candidate;
							}
							candidates.add(candidate);
						}
						// 构造方法中的参数为 0 实际就是指默认的构造方法呢
						// 4 = {Constructor@2510} "public org.springframework.waf.entity.TestBo()"
						else if (candidate.getParameterCount() == 0) {
							defaultConstructor = candidate;
						}
					}
					if (!candidates.isEmpty()) {
						// Add default constructor to list of optional constructors, as fallback.
						if (requiredConstructor == null) {
							if (defaultConstructor != null) {
								candidates.add(defaultConstructor);
							}
							else if (candidates.size() == 1 && logger.isInfoEnabled()) {
								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.toArray(new Constructor<?>[0]);
					}
					// 一个有参的构造函数
					else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
						candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
					}
					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};
					}
					else {
						candidateConstructors = new Constructor<?>[0];
					}
					this.candidateConstructorsCache.put(beanClass, candidateConstructors);
				}
			}
		}
		return (candidateConstructors.length > 0 ? candidateConstructors : null);
	}

我们先看下代码中提到的这个方法

Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);

这个方法的解释我们点进去看看,

/**
	 * Return the primary constructor of the provided class. For Kotlin classes, this
	 * returns the Java constructor corresponding to the Kotlin primary constructor
	 * (as defined in the Kotlin specification). Otherwise, in particular for non-Kotlin
	 * classes, this simply returns {@code null}.
	 * @param clazz the class to check
	 * @since 5.0
	 * @see <a href="http://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin docs</a>
	 */
	@SuppressWarnings("unchecked")
	@Nullable
	public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
		Assert.notNull(clazz, "Class must not be null");
		if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
			Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
			if (kotlinPrimaryConstructor != null) {
				return kotlinPrimaryConstructor;
			}
		}
		return null;
	}

通过注释的翻译得到的结果是返回 null 既然这个方法返回的是空,通过判断合适的构造方法在下面的else if 的结果中只有两种情况

第一种是提供了默认的构造方法还包含其它的构造方法 会返回 null,最后创建默认的构造方法

第二种是有且仅有一个带参数的构造方法,最后创建当前构造方法
而结果也是确实返回了空

所以创建了一个默认的构造方法。

我们再看看第三种情况 只去掉一个默认的构造方法会有什么结果(还有7个)
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

这里还是会返回空进入到这一行return instantiateBean(beanName, mbd);那为什么提供了默认的构造方法返回空之后会正常创建呢,而没加默认的构造方法返回空后会报异常呢。答案就在这儿,我们顺着点进去看看第78行是去获取,不是创建,所以没获取到会报异常(但是如果没有构造方法,才会正常获取到默认的)

	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

第四种 我们为其中的某一个构造方法手动加上@Autowired 注解默认属性为true的情况下,这种情况下根据上面的第二种也能猜到

1.加在默认的构造方法上面,感觉没什么意义

2.加在某一个带参数的构造方法上面,那么这种情况和 当且仅当只有一个带参数的构造方法时 有异曲同工之妙呢,返回当前构造方法

同理如果为其中的某一个构造方法手动加上@Autowired 注解默认属性为false的情况下(当且仅当只有一个带参数的构造方法)

小提示:8个构造方法中有一个构造方法参数是String 类型 ,根据解决循环依赖的逻辑,String 类型的这个对象不在spring容器中所有不会选择这个构造方法,如果有且仅有这个构造方法 和 在这个构造方法上加上@Autowired 属性为true的注解来指定。那么也会报错的。

第五种 为多个构造方法加上@Autowired 属性为true 的注解

结果显而易见解析第一个@Autowired 属性为true 的注解 时已经赋值给requiredConstructor 了,所以第二次的时候会报错。

第六种 为多个构造方法加上@Autowired 属性为false,其中一个为 @Autowired 属性为true 的注解,那么我们可以看到在上图的逻辑中当属性为false的注解的构造方法时,会往candidates集合里面放,当属性为true 的注解时会判断candidates集合有值就会报错

1. @Autowired 属性为true 的注解最先判断,那么requiredConstructor会进行赋值,再判断@Autowired 属性为false的注解时会判断requiredConstructor是否为空。报错

2.@Autowired 属性为false的注解最先判断,会往candidates集合里面放,再判断@Autowired 属性为true 的注解时会判断candidates集合有值。报错

3.交替解析。报错

第七种 为多个构造方法加上@Autowired 属性为false 有多个会怎么样,会将默认的构造方法也放进去,作为合适的构造方法进行第二次推断。(自动装配--参数最长的那个构造方法)

看下第二次推断的方法,我们下一篇文章进行介绍。

	/**
	 * "autowire constructor" (with constructor arguments by type) behavior.
	 * Also applied if explicit constructor argument values are specified,
	 * matching all remaining arguments with beans from the bean factory.
	 * <p>This corresponds to constructor injection: In this mode, a Spring
	 * bean factory is able to host components that expect constructor-based
	 * dependency resolution.
	 * @param beanName the name of the bean
	 * @param mbd the merged bean definition for the bean
	 * @param chosenCtors chosen candidate constructors (or {@code null} if none)
	 * @param explicitArgs argument values passed in programmatically via the getBean method,
	 * or {@code null} if none (-> use constructor argument values from bean definition)
	 * @return a BeanWrapper for the new instance
	 */
	public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@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) {
			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) {
						argsToResolve = mbd.preparedConstructorArguments;
					}
				}
			}
			if (argsToResolve != null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
			}
		}

		if (constructorToUse == null || argsToUse == null) {
			// Take specified constructors, if any.
			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;
				}
			}

			// 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 {
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}

			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE;
			Set<Constructor<?>> ambiguousConstructors = null;
			LinkedList<UnsatisfiedDependencyException> causes = null;

			for (Constructor<?> candidate : candidates) {
				Class<?>[] paramTypes = candidate.getParameterTypes();

				if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
					// Already found greedy constructor that can be satisfied ->
					// do not look any further, there are only less greedy constructors left.
					break;
				}
				if (paramTypes.length < minNrOfArgs) {
					continue;
				}

				ArgumentsHolder argsHolder;
				if (resolvedValues != null) {
					try {
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
						if (paramNames == null) {
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if (pnd != null) {
								paramNames = pnd.getParameterNames(candidate);
							}
						}
						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 LinkedList<>();
						}
						causes.add(ex);
						continue;
					}
				}
				else {
					// Explicit arguments given -> arguments length must match exactly.
					if (paramTypes.length != explicitArgs.length) {
						continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}

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

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

猜你喜欢

转载自blog.csdn.net/qq_38108719/article/details/103214945
今日推荐