耀眼的星星并不是最高的
此篇文章我们来介绍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> 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 Kotlin docs
*/
@SuppressWarnings("unchecked")
@Nullable
public static Constructor findPrimaryConstructor(Class clazz) {
Assert.notNull(clazz, "Class must not be null");
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
Constructor 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>) 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.
* 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> ambiguousConstructors = null;
LinkedList 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;
}