spring-ioc-inferred constructor-manual assembly



 

The dazzling stars are not the highest

In this article, we will introduce one of the essence of spring ioc, how to infer the constructor, which is divided into manual assembly and automatic assembly into the source code.

We know that in the life cycle of a spring bean, the object is initialized first and then the attributes are assembled, so we use the object returned from the above construction method as the entry point.

The test environment this time is

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

Automatic assembly environment added

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

We will enter the following method through the above breakpoint (the upper part)

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

First use singleton test once

Let's change it to the prototype object @Scope("prototype"). The initialization of the spring prototype object is different from that of the singleton. It needs to be initialized when 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");//第二次断点
	}
}

The first time it should be the same as the result in the figure above

After running, enter the next breakpoint

Let’s go to this place for this piece of code, because the following singleton selection construction method will also have the same call chain, change it back and look at the lower part of this method.

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

Let's enter the first line of code to see how spring chooses a suitable construction method (there are 8 construction methods in our current entity class)

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

Let's first look at this method mentioned in the code

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

Let’s click in and take a look at the explanation of this method.

/**
	 * 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;
	}

The result obtained by the translation of the comment is to return null. Since this method returns empty, there are only two cases in the result of the following else if by judging the appropriate construction method

The first is to provide a default construction method and also include other construction methods that will return null, and finally create a default construction method

The second is to have one and only one construction method with parameters, and finally create the current construction method
and the result is indeed empty

So a default construction method was created.

Let's take a look at the third case and what will
happen if only one default constructor is removed (there are 7 more) Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

Here it will still return empty and enter this line return instantiateBean(beanName, mbd); then why is it created normally after the default constructor is provided and returns empty, and an exception will be reported after the default constructor returns empty. The answer is here, let’s go in and see if the 78th line is to get it, not to create it, so an exception will be reported if it is not obtained (but if there is no construction method, the default will be obtained normally)

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

In the fourth case, we manually add @Autowired annotation to one of the construction methods. The default attribute is true. In this case, we can also guess according to the second method above.

1. Add to the default construction method, it feels meaningless

2. Add to a parameterized construction method, then this situation has the same effect as if and only if there is only one parameterized construction method, return to the current construction method

Similarly, if the @Autowired annotation is manually added to one of the construction methods, the default attribute is false (if and only if there is only one construction method with parameters)

Tips: One of the eight construction methods has a parameter of type String. According to the logic of resolving circular dependencies, this object of type String is not in the spring container. This construction method will not be selected. If there is and only this construction method and Add the annotation that the @Autowired attribute is true to this construction method to specify. Then an error will be reported.

The fifth is to add annotations that @Autowired attribute is true for multiple construction methods

The result is obviously that the first annotation whose @Autowired attribute is true is already assigned to the requiredConstructor when parsing, so an error will be reported the second time.

The sixth method is to add @Autowired attribute to false for multiple construction methods, one of which is the annotation with @Autowired attribute being true, then we can see that in the logic of the above figure, when the attribute is false, the annotation construction method will Put it in the candidates collection, when the attribute is true, it will judge that the candidates collection has a value and an error will be reported

1. The annotation whose @Autowired attribute is true is judged first, then the requiredConstructor will be assigned, and then when the annotation with the @Autowired attribute is false, it will be judged whether the requiredConstructor is empty. Report an error

2. The annotation whose @Autowired attribute is false is judged first, and will be placed in the candidates collection, and then when the annotation with the @Autowired attribute is true, it will be judged that the candidates collection has a value. Report an error

3. Alternate analysis. Report an error

The seventh method is for multiple construction methods plus @Autowired attribute is false. What happens if there are multiple construction methods, the default construction method will also be put in, as a suitable construction method for the second inference. (Automatic assembly-the construction method with the longest parameter)

Look at the second inference method, we will introduce it in the next article.

	/**
	 * "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;
	}

 

Guess you like

Origin blog.csdn.net/qq_38108719/article/details/103214945