Spring之推断构造方法源码

文章目录

    • 一、 简介
      • 1. 内容回顾
      • 2. Spring推断构造方法
    • 二、 源码分析

一、 简介

1. 内容回顾

前面分析了Spring的Bean的生命周期的源码,然后分析了依赖注入源码,以及依赖注入的过程中循环依赖Spring的解决方案。在介绍Bean的生命周期中,我们并没有详细介绍Spring底层是如何真正创建Bean的,其实Spring底层创建Bean和我们new一个对象是一样的,也需要使用到构造函数,这篇文章就详细分析这一部分的源码,这样Bean的生命周期的所有相关的源码就几乎分析完了。

2. Spring推断构造方法

Spring推断构造方法的大致流程如下:
在这里插入图片描述

首先创建AService类:

@Component
public class AService {@AutowiredBService bService;//空构造方法public AService(){System.out.println("AService的无参构造方法");}//有参构造方法public AService(BService bService){System.out.println("AService的有参构造方法");this.bService=bService;}public void test(){System.out.println(bService);}
}

AService有两个构造方法,一个是无参的构造方法,一个是有参的构造方法

创建BService:

@Component
public class BService {
}

然后我们测试一下:

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 获取 BoxService beanAService aService = (AService) applicationContext.getBean("AService");// 关闭 ApplicationContextapplicationContext.close();}
}

在这里插入图片描述

由输出结果我们可以看出,在创建AService这个Bean时,默认调用了AService的无参数构造方法。现在我们把无参数的构造方法去掉,再次观察结果。

在这里插入图片描述

发现此时Spring调用了有参数的构造方法,此时我们再加入一个CService

@Component
public class CService {
}

然后修改AService代码

@Component
public class AService {@AutowiredBService bService;@AutowiredCService cService;//	//空构造方法
//	public AService(){
//		System.out.println("AService的无参构造方法");
//	}//有参构造方法public AService(BService bService) {System.out.println("AService的有参构造方法1");this.bService = bService;}//有参构造方法public AService(CService cService) {System.out.println("AService的有参构造方法2");this.cService = cService;}public AService(BService bService, CService cService){System.out.println("AService的有参构造方法3");this.bService=bService;this.cService=cService;}public void test() {System.out.println(bService);}
}

再次测试
在这里插入图片描述

发现直接报错了,说明Spring在多个构造方法中没有推断出到底使用哪一个构造方法。

我们可以在我们需要的构造方法上加一个@Autowired注解告诉Spring我们要使用哪一个构造方法。

@Component
public class AService {@AutowiredBService bService;@AutowiredCService cService;//	//空构造方法
//	public AService(){
//		System.out.println("AService的无参构造方法");
//	}//有参构造方法public AService(BService bService) {System.out.println("AService的有参构造方法1");this.bService = bService;}//有参构造方法public AService(CService cService) {System.out.println("AService的有参构造方法2");this.cService = cService;}@Autowiredpublic AService(BService bService, CService cService) {System.out.println("AService的有参构造方法3");this.bService = bService;this.cService = cService;}public void test() {System.out.println(bService);}
}

在这里插入图片描述
同时也可以通过getBean方法来指定我们的构造方法,注意此时AService要改为懒加载的,如果不是懒加载AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);就默认将我们的非懒加载的Bean初始化完了,所以下面测试代码会直接报错,所以需要在AService上加一个@Lazy

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);// 获取 BoxService beanAService aService = (AService) applicationContext.getBean("AService",new CService());// 关闭 ApplicationContextapplicationContext.close();}
}

在这里插入图片描述
修改AService

public class AService {@AutowiredBService bService;@AutowiredCService cService;//	//空构造方法
//	public AService(){
//		System.out.println("AService的无参构造方法");
//	}//有参构造方法public AService(BService bService) {System.out.println("AService的有参构造方法1");this.bService = bService;}//有参构造方法public AService(CService cService) {System.out.println("AService的有参构造方法2");this.cService = cService;}public AService(BService bService, CService cService) {System.out.println("AService的有参构造方法3");this.bService = bService;this.cService = cService;}public void test() {System.out.println(bService);}
}

现在AService并不是一个Bean,我们修改测试类

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(AppConfig.class);AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(AService.class);//指定创建bean时,构造方法的入参值beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new BService());applicationContext.registerBeanDefinition("AService",beanDefinition);applicationContext.refresh();AService aService = (AService) applicationContext.getBean("AService");applicationContext.close();}
}

上面我们自己定义了一个BeanDefinition,然后注册到容器中,同样最后也可以拿到创建好的Bean

在这里插入图片描述
下面对上面内容总结一下:

  • 默认情况使用空构造方法,或使用唯一的那一个有参的构造方法
  • 如果指定了构造方法的入参值,通过getBean方法或者BeanDefinition.getConstructorArgumentValues()指定,那就用所匹配的构造方法
  • 如果要Spring自己选定构造方法以及构造方法的入参值,使用autowired="constructor
  • 通过@Autowired注解指定了某个构造方法,但是值Spring自动来找

注意加@Autowired在构造方法或配置autowired="constructor"在xml配置文件中,这两个是有区别的,前者会指定要用那个构造方法(这个是定死的),然后spring自动找对应的参数值,后者构造方法和参数值都是Spring自己去确定的(默认是选参数最多的构造方法)。

上面介绍了多种指定创建Bean时指定构造方法的多种方式,下面我们就针对这些方式详细分析一下Spring底层时怎么做的。

二、 源码分析

上面内容都是创建Bean的内容,所以我们先进入doCreateBean方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// 实例化bean// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {// 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中)instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {// 创建Bean实例instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 后置处理合并后的BeanDefinition// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// 为了解决循环依赖提前缓存单例创建工厂// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 循环依赖-添加到三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// 属性填充populateBean(beanName, mbd, instanceWrapper);// 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {// beanName被哪些bean依赖了,现在发现beanName所对应的bean对象发生了改变,那么则会报错String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}

然后实际去创建Bean是在instanceWrapper = createBeanInstance(beanName, mbd, args);这句代码。

/**
beanName:传入的beanname
RootBeanDefinition:传入的BeanDefinition
Object[] args:getBean传入的参数
**/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {//拿到当前beandefinition对应的那个类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());}// BeanDefinition中添加了Supplier,则调用Supplier来得到对象Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// @Bean对应的BeanDefinitionif (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...// 一个原型BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来,避免每次都进行构造方法推断boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入)if (autowireNecessary) {// 方法内会拿到缓存好的构造方法的入参return autowireConstructor(beanName, mbd, null, null);}else {// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化return instantiateBean(beanName, mbd);}}// 如果没有找过构造方法,那么就开始找了// Candidate constructors for autowiring?// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入// 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了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提供了一个不太有作用的机制

// BeanDefinition中添加了Supplier,则调用Supplier来得到对象Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}

Supplier 是 Java 8 引入的函数式接口,用于提供对象的实例。在这里,instanceSupplier 是一个 Supplier<?> 类型的对象,它封装了创建 Bean 实例的逻辑。

public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(AppConfig.class);AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(AService.class);beanDefinition.setInstanceSupplier(new Supplier<Object>() {@Overridepublic Object get() {return new BService();}});applicationContext.registerBeanDefinition("AService",beanDefinition);applicationContext.refresh();BService aService = (BService) applicationContext.getBean("AService");applicationContext.close();}
}

上面代码本来是想创建一个AService的Bean,我使用Supplier却让里面封装来一个BService。继续回到源码。下面就是创建Bean的核心代码。

boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;// autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值autowireNecessary = mbd.constructorArgumentsResolved;}}}

上面最核心的是BeanDefitnition提供的两个缓存,第一个是mbd.constructorArgumentLock,它缓存了BeanDefinition的构造方法,mbd.constructorArgumentsResolved缓存了构造方法的参数。这两个缓存有什么用呢,考虑一种场景,如果我现在AService是原型bean,我需要多次获取AService对象(使用getBean方法),所以在第一次获取时我需要推断构造方法,然后找到合适的构造方法以及参数,并将其存入到上面的两个缓存中,在以后我多次获取AService对象,我只需要从缓存中拿就可以了,提高了推断构造方法的效率。(注意如果getBean我们没有给额外参数,这个缓存才生效)继续回到源码。

if (resolved) {// 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入)if (autowireNecessary) {// 方法内会拿到缓存好的构造方法的入参return autowireConstructor(beanName, mbd, null, null);}else {// 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化return instantiateBean(beanName, mbd);}}

当我们传入的getBean没有提供额外的参数(只提供了beaname),我们就会执行完前面缓存的逻辑,缓存执行完后resolved=true,所以会进入上面代码,上面代码首先判断autowireNecessary,如果我们默认构造函数是无参数的autowireNecessary就会为false,所以就会执行instantiateBean方法,使用无参数的构造方法初始化(后面再讲这个方法)。如果只true,表示是有参数的构造函数,所以就会执行autowireConstructor,这个方法很重要,后面的逻辑也会调用,所以后面再讲。继续回到createBeanInstance源码。

// 如果没有找过构造方法,那么就开始找了// Candidate constructors for autowiring?// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法// 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入// 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了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);}

首先上面我们已经讲完了(缓存中缓存了默认构造方法的情况),上面代码就开始执行案例中的复杂情况,即多个构造方法的情况,首先我们需要知道有哪些构造方法是可以用的,这个逻辑的实现就是Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);。

@Nullableprotected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)throws BeansException {if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);if (ctors != null) {return ctors;}}}return null;}

然后调用的核心函数就是bp.determineCandidateConstructors,可以发现这个方法是AutowiredAnnotationBeanPostProcessor 对象的方法,那为什么要AutowiredAnnotationBeanPostProcessor这个类来实现找构造函数的逻辑嫩?我们知道这个类是处理@Autowired注解的,所以这个方法在这个类中实现的逻辑就是找到构造方法上面有@Autowired注解的。

@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)throws BeanCreationException {// Let's check for lookup methods here...if (!this.lookupMethodsChecked.contains(beanName)) {// 判断beanClass是不是java.开头的类,比如Stringif (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {try {Class<?> targetClass = beanClass;do {// 遍历targetClass中的method,查看是否写了@Lookup方法ReflectionUtils.doWithLocalMethods(targetClass, method -> {Lookup lookup = method.getAnnotation(Lookup.class);if (lookup != null) {Assert.state(this.beanFactory != null, "No BeanFactory available");// 将当前method封装成LookupOverride并设置到BeanDefinition的methodOverrides中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);}}this.lookupMethodsChecked.add(beanName);}//判断我之前有没有找过,如果找过就可以从缓存中直接拿到Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);if (candidateConstructors == null) {//如果没有找过,就开始第一次寻找(这里访问里公共资源,所以需要加锁保证线程安全)synchronized (this.candidateConstructorsCache) {//这里就是DCL机制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);}List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);// 用来记录required为true的构造方法,一个类中只能有一个required为true的构造方法Constructor<?> requiredConstructor = null;// 用来记录默认无参的构造方法Constructor<?> defaultConstructor = null;// kotlin相关,不用管Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);int nonSyntheticConstructors = 0;// 遍历找到的每个构造方法for (Constructor<?> candidate : rawCandidates) {if (!candidate.isSynthetic()) {// 记录一下普通的构造方法nonSyntheticConstructors++;}else if (primaryConstructor != null) {continue;}// 当前遍历的构造方法是否写了@AutowiredMergedAnnotation<?> ann = findAutowiredAnnotation(candidate);//如果没有找到加@Autowired注解的构造函数,如果这个类是代理类就找被代理对象的构造方法上面有没有@Autowired注解if (ann == null) {// 如果beanClass是代理类,则得到被代理的类的类型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...}}}// 当前构造方法上加了@Autowiredif (ann != null) {// 整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法if (requiredConstructor != null) {//requiredConstructor != null说明前面遍历到的构造方法有一个加了@Autowire(require=true),由于整个类只能存在一个require=true,所以会报错throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}boolean required = determineRequiredStatus(ann);if (required) {if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructors: " + candidates +". Found constructor with 'required' Autowired annotation: " +candidate);}// 记录唯一一个required为true的构造方法requiredConstructor = candidate;}// 记录所有加了@Autowired的构造方法,不管required是true还是false// 如果默认无参的构造方法上也加了@Autowired,那么也会加到candidates中candidates.add(candidate);// 从上面代码可以得到一个结论,在一个类中,要么只能有一个required为true的构造方法,要么只能有一个或多个required为false的方法}//如果当前类没有@Autowire注解,且参数个数为0,说明当前类有无参构造方法,spring就会使用这个无参构造方法作为默认的初始化构造方法else if (candidate.getParameterCount() == 0) {// 记录唯一一个无参的构造方法defaultConstructor = candidate;}// 有可能存在有参、并且没有添加@Autowired的构造方法}if (!candidates.isEmpty()) {// 如果不存在一个required为true的构造方法,则所有required为false的构造方法和无参构造方法都是合格的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));}}// 如果只存在一个required为true的构造方法,那就只有这一个是合格的candidateConstructors = candidates.toArray(new Constructor<?>[0]);}// 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {candidateConstructors = new Constructor<?>[] {rawCandidates[0]};}// primaryConstructor不用管else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};}// primaryConstructor不用管else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {candidateConstructors = new Constructor<?>[] {primaryConstructor};}else {// 如果有多个有参、并且没有添加@Autowired的构造方法,是会返回空的candidateConstructors = new Constructor<?>[0];}this.candidateConstructorsCache.put(beanClass, candidateConstructors);}}}return (candidateConstructors.length > 0 ? candidateConstructors : null);}

上面的方法的流程我可以总结为下面的图:
在这里插入图片描述
回到createBeanInstance方法

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);// 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入// 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法// 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了// 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了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);}

ctors存储了前逻辑判断出来的构造方法,然后进入if判断,如果ctors不为空且满足if的任意一个条件就调用autowireConstructor方法,否则就直接调用instantiateBean使用无参的构造方法实例化。

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {try {Object beanInstance;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),getAccessControlContext());}else {// 默认是CglibSubclassingInstantiationStrategybeanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);}}

上面创建Bean的核心代码是beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);,这里就是使用的Cglib动态代理技术来创建Bean实例。

@Overridepublic Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// Don't override the class with CGLIB if no overrides.// 判断当前BeanDefinition对应的beanClass中是否存在@Lookup的方法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.// 如果存在@Lookup,则会生成一个代理对象return instantiateWithMethodInjection(bd, beanName, owner);}}

然后继续调用BeanUtils.instantiateClass(constructorToUse);传入的参数就是前面获得的无参数的构造方法。

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {Assert.notNull(ctor, "Constructor must not be null");try {ReflectionUtils.makeAccessible(ctor);if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {return KotlinDelegate.instantiateClass(ctor, args);}else {Class<?>[] parameterTypes = ctor.getParameterTypes();Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");Object[] argsWithDefaultValues = new Object[args.length];for (int i = 0 ; i < args.length; i++) {if (args[i] == null) {Class<?> parameterType = parameterTypes[i];argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);}else {argsWithDefaultValues[i] = args[i];}}//根据构造放阿福进行真正的实例化return ctor.newInstance(argsWithDefaultValues);}}catch (InstantiationException ex) {throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);}catch (IllegalAccessException ex) {throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);}catch (IllegalArgumentException ex) {throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);}catch (InvocationTargetException ex) {throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());}}

上面代码就完成了使用无参构造方法的实例化,继续回到createBeanInstance。如果我们返回来的构造方法集合ctors不为空,就会执行autowireConstructor这一核心方法,执行真正的构造方法推断逻辑。

/**
beanName:bean的名称
mbd:BeanDefitnition
chosenCtors:可行的构造函数候选集合(前面的逻辑得出来的)
explicitArgs:getBean方法额外的参数
**/
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;// 如果getBean()传入了args,那构造方法要用的入参就直接确定好了if (explicitArgs != null) {//getBean方法传了,Spring就不需要自己推断了,直接使用getBean传入的即可argsToUse = explicitArgs;}else {//如果getbean没有指定构造方法的参数,如果没有传入参数,则尝试从缓存中获取构造函数和参数信息。如果缓存中有,直接使用;否则,调用 resolvePreparedArguments 进行解析。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);}}// 如果没有确定要使用的构造方法,或者确定了构造方法但是所要传入的参数值没有确定if (constructorToUse == null || argsToUse == null) {// Take specified constructors, if any.// 如果没有指定构造方法,那就获取beanClass中的所有构造方法所谓候选者Constructor<?>[] candidates = chosenCtors;if (candidates == null) {//如果我们没有手动指定构造方法,就获取当前bean得全部构造方法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;}//直接调用instantiate进行无参构造方法的实例化bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));return bw;}}// autowiring表示是否支持自动注入,如果是true,那么我们没指定的参数spring会帮我们自动注入boolean autowiring = (chosenCtors != null ||mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);ConstructorArgumentValues resolvedValues = null;// 确定要选择的构造方法的参数个数的最小值,后续判断候选构造方法的参数个数如果小于minNrOfArgs,则直接pass掉int minNrOfArgs;if (explicitArgs != null) {// 如果直接传了构造方法参数值,那么所用的构造方法的参数个数肯定不能少于minNrOfArgs = explicitArgs.length;}else {// 如果通过BeanDefinition传了构造方法参数值,因为有可能是通过下标指定了,比如0位置的值,2位置的值,虽然只指定了2个值,但是构造方法的参数个数至少得是3个ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();resolvedValues = new ConstructorArgumentValues();// 处理RuntimeBeanReference minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}// 对候选构造方法进行排序,public的方法排在最前面,都是public的情况下参数个数越多越靠前AutowireUtils.sortConstructors(candidates);int minTypeDiffWeight = Integer.MAX_VALUE;Set<Constructor<?>> ambiguousConstructors = null;Deque<UnsatisfiedDependencyException> causes = null;// 遍历每个候选构造方法,进行筛选for (Constructor<?> candidate : candidates) {// 参数个数int parameterCount = candidate.getParameterCount();// 本次遍历时,之前已经选出来了所要用的构造方法和入参对象,并且入参对象个数比当前遍历到的这个构造方法的参数个数多,则不用再遍历,退出循环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;}// 如果参数个数小于所要求的参数个数,则遍历下一个,这里考虑的是同时存在public和非public的构造方法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);}}// 根据参数类型、参数名找到对应的bean对象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 ArrayDeque<>(1);}causes.add(ex);continue;}}else {// Explicit arguments given -> arguments length must match exactly.// 在调getBean方法时传入了参数值,那就表示只能用对应参数个数的构造方法if (parameterCount != explicitArgs.length) {continue;}// 不用再去BeanFactory中查找bean对象了,已经有了,同时当前正在遍历的构造方法就是可用的构造方法argsHolder = new ArgumentsHolder(explicitArgs);}// 当前遍历的构造方法所需要的入参对象都找到了,根据参数类型和找到的参数对象计算出来一个匹配值,值越小越匹配// Lenient表示宽松模式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);}}// 遍历结束   x// 如果没有可用的构造方法,就取记录的最后一个异常并抛出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 on bean class [" + mbd.getBeanClassName() + "] " +"(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 on bean class [" + mbd.getBeanClassName() + "] " +"(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;}

argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,会根据参数名字和类型去容器中找bean对象。

private ArgumentsHolder createArgumentArray(String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();TypeConverter converter = (customConverter != null ? customConverter : bw);ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);Set<String> autowiredBeanNames = new LinkedHashSet<>(4);// 遍历构造方法的参数类型for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {// 拿到具体的参数类型和参数名Class<?> paramType = paramTypes[paramIndex];String paramName = (paramNames != null ? paramNames[paramIndex] : "");// Try to find matching constructor argument value, either indexed or generic.ConstructorArgumentValues.ValueHolder valueHolder = null;// 如果在BeanDefinition中指定了构造方法参数值,则拿到具体的对象if (resolvedValues != null) {valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);// If we couldn't find a direct match and are not supposed to autowire,// let's try the next generic, untyped argument value as fallback:// it could match after type conversion (for example, String -> int).if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);}}if (valueHolder != null) {// We found a potential match - let's give it a try.// Do not consider the same value definition multiple times!usedValueHolders.add(valueHolder);Object originalValue = valueHolder.getValue();Object convertedValue;if (valueHolder.isConverted()) {convertedValue = valueHolder.getConvertedValue();args.preparedArguments[paramIndex] = convertedValue;}else {// 如果需要进行类型转化,则转化MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);try {convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);}catch (TypeMismatchException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Could not convert argument value of type [" +ObjectUtils.nullSafeClassName(valueHolder.getValue()) +"] to required type [" + paramType.getName() + "]: " + ex.getMessage());}Object sourceHolder = valueHolder.getSource();if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();args.resolveNecessary = true;args.preparedArguments[paramIndex] = sourceValue;}}// 当前所遍历的参数所对应的参数值args.arguments[paramIndex] = convertedValue;args.rawArguments[paramIndex] = originalValue;}else {MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);// No explicit match found: we're either supposed to autowire or// have to fail creating an argument array for the given constructor.if (!autowiring) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),"Ambiguous argument values for parameter of type [" + paramType.getName() +"] - did you specify the correct bean references as arguments?");}try {// 根据方法参数类型和名字从BeanFactory中匹配Bean对象Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);// 当前所遍历的参数所对应的参数值args.rawArguments[paramIndex] = autowiredArgument;args.arguments[paramIndex] = autowiredArgument;args.preparedArguments[paramIndex] = autowiredArgumentMarker;args.resolveNecessary = true;}catch (BeansException ex) {throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);}}}for (String autowiredBeanName : autowiredBeanNames) {this.beanFactory.registerDependentBean(autowiredBeanName, beanName);if (logger.isDebugEnabled()) {logger.debug("Autowiring by type from bean name '" + beanName +"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +" to bean named '" + autowiredBeanName + "'");}}return args;}

上面就是解析某个构造函数的参数。在解析的过程中,它会拿用户传入的构造方法参数值与该构造方法的参数值进行比较,if (!autowiring) {标记来判断,对于缺少的参数是否可以允许spring来自动注入,底层用的找bean得代码和依赖注入那一套一样。继续回到autowireConstructor方法。

for (Constructor<?> candidate : candidates) {// 参数个数int parameterCount = candidate.getParameterCount();// 本次遍历时,之前已经选出来了所要用的构造方法和入参对象,并且入参对象个数比当前遍历到的这个构造方法的参数个数多,则不用再遍历,退出循环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;}// 如果参数个数小于所要求的参数个数,则遍历下一个,这里考虑的是同时存在public和非public的构造方法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);}}// 根据参数类型、参数名找到对应的bean对象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 ArrayDeque<>(1);}causes.add(ex);continue;}}else {// Explicit arguments given -> arguments length must match exactly.// 在调getBean方法时传入了参数值,那就表示只能用对应参数个数的构造方法if (parameterCount != explicitArgs.length) {continue;}// 不用再去BeanFactory中查找bean对象了,已经有了,同时当前正在遍历的构造方法就是可用的构造方法argsHolder = new ArgumentsHolder(explicitArgs);}

上面的逻辑就是遍历每一个候选的构造方法,如果没有在getbean方法中指定参数值就会if (resolvedValues != null) {逻辑,否则执行下面代码:

// Explicit arguments given -> arguments length must match exactly.// 在调getBean方法时传入了参数值,那就表示只能用对应参数个数的构造方法if (parameterCount != explicitArgs.length) {continue;}// 不用再去BeanFactory中查找bean对象了,已经有了,同时当前正在遍历的构造方法就是可用的构造方法argsHolder = new ArgumentsHolder(explicitArgs);

上面代码如果当前构造函数的参数和传入的个数相同,就直接用当前的构造函数,然后参数值就是我们传入的参数。然后执行后面的逻辑:

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

如果我们有多个构造函数匹配,它会根据匹配度计算最合适的那一个构造函数。如果有分数相同的就会记录到(且不是严格模式)ambiguousConstructors这个集合中。继续:

假设bean的类型为A,A的父类是B,B的父类是C,同时A实现了接口D 如果构造方法的参数类型为 A,那么完全匹配,得分为0 如果构造方法的参数类型为B,那么得分为2 如果构造方法的参数类型为 C,那么得分为4 如果构造方法的参数类型为D,那么得分为1。所以,我们可以发现,越匹配分数越低。

//如果有多个匹配度相同的构造函数,它会使用最先匹配的那一个,作为本次要初始化的构造函数// 如果没有通过getBean方法传入参数,并且找到了构造方法以及要用的入参对象则缓存if (explicitArgs == null && argsHolderToUse != null) {argsHolderToUse.storeCache(mbd, constructorToUse);}}

最后使用选定的构造方法和参数初始化bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/605338.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三维模型的几何坐标纠正应用探讨

三维模型的几何坐标纠正应用探讨 倾斜摄影三维模型数据的几何坐标纠正应用分析 近年来&#xff0c;倾斜摄影技术在三维数据采集设备中得到广泛应用。倾斜摄影技术通过在飞行平台上搭载多台传感器&#xff0c;从不同角度采集影像&#xff0c;相比传统的摄影测量&#xff0c;倾斜…

每日算法打卡:数的三次方根 day 7

文章目录 原题链接题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 题目分析示例代码 原题链接 790. 数的三次方根 题目难度&#xff1a;简单 题目描述 给定一个浮点数 n&#xff0c;求它的三次方根。 输入格式 共一行&#xff0c;包含一个浮…

第17课 为rtsp流加入移动检测功能

在上节课&#xff0c;我们成功拿到了rtsp视频和音频流&#xff0c;在第13课&#xff0c;我们为普通的usb摄像头加上了移动检测功能&#xff0c;那能不能给rtsp摄像头也加上移动检测功能以实现一些好玩的应用呢&#xff1f;答案是肯定的&#xff0c;在usb摄像头检测中&#xff0…

vue结合Cesium加载gltf模型

Cesium支持什么格式&#xff1f; Cesium支持的格式包括&#xff1a;3D模型格式&#xff08;如COLLADA、gITF、OBJ&#xff09;、影像格式&#xff08;如JPEG、PNG、GeoTIFF&#xff09;、地形格式&#xff08;如STL、Heightmap&#xff09;、矢量数据格式&#xff08;如GeoJSON…

初识Linux shell

Linux初探 Linux系统可以划分为4个部分&#xff1a; Linux内核&#xff1a;Linux系统的核心&#xff0c;控制着系统的所有硬件和软件&#xff0c;在必要时分配硬件&#xff0c;并根据需要执行软件。 内核主要功能&#xff1a; 系统内存管理&#xff1a;内核通过硬件上称为交换…

labelImg的安装与使用

目录 1、查看本机是否安装labelImg 2、安装labelImg 3、创建自己的数据集 3.1 建立新文件夹 3.2 打开labelImg 注意&#xff1a;出现闪退的情况处理。 4、文件格式转换 4.1 修改文件夹路径 4.2 新建datasets文件夹 4.3 修改图片路径 4.4 执行 1、查看本机是否安装la…

【Origin绘图1】环形图

环形图绘制 Origin绘制环形图案例 MATLAB绘制环形饼状图案例 参考 环形图如下&#xff0c;可分析不同年份各组分变化情况&#xff1a; Origin绘制环形图 貌似对Origin版本有要求&#xff0c;下载的2019版并无环形图绘制工具。因此&#xff0c;重新下载了2022版本。 案例 第…

Python 利用PYQT5设计基于RSA算法盲签名的匿名化电子支付系统设计与实现

基于RSA算法的盲签名算法 David Chaum 于1982年提出盲签名的概念&#xff0c;并利用RSA算法设计了第一个盲签名方案. 该方案的安全性基于大整数分解问题 盲签名的步骤 1.密钥生成 签名者执行以下步骤生成密钥对: ①签名者选择两个大素数p,q&#xff0c; 计算npq&#xff0…

【OpenVINO 】在 MacOS 上编译 OpenVINO C++ 项目

前言 英特尔公司发行的模型部署工具OpenVINO™模型部署套件&#xff0c;可以实现在不同系统环境下运行&#xff0c;且发布的OpenVINO™ 2023最新版目前已经支持MacOS系统并同时支持在苹果M系列芯片上部署模型。在该项目中&#xff0c;我们将向大家展示如何在MacOS系统、M2芯片的…

鸿鹄电子招投标系统源码实现与立项流程:基于Spring Boot、Mybatis、Redis和Layui的企业电子招采平台

随着企业的快速发展&#xff0c;招采管理逐渐成为企业运营中的重要环节。为了满足公司对内部招采管理提升的要求&#xff0c;建立一个公平、公开、公正的采购环境至关重要。在这个背景下&#xff0c;我们开发了一款电子招标采购软件&#xff0c;以最大限度地控制采购成本&#…

NFS 共享存储实验

一、服务器部署 第一步、安装nfs和rpcbind包 [rootserver ~]# yum install -y nfs-utils rpcbind截图&#xff1a; 第二步、这里选择一个 lvm 挂载点做 NFS 共享目录 [rootserver ~]# df -HT截图&#xff1a; 第三步、修改配置文件 [rootserver ~]# vi /etc/exports /home …

神经网络的核心:简单易懂理解 PyTorch 非线性激活函数

目录 torch.nn子函数非线性激活详解 nn.Softmin Softmin 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.Softmax Softmax 函数简介 函数工作原理 参数详解 使用技巧与注意事项 示例代码 nn.Softmax2d Softmax2d 函数简介 函数工作原理 输入…

2024最新前端源码分享(附效果图及在线演示)

分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 粒子文字动画特效 基于canvas实现的粒子文字动画特效 会来回切换设定的文字特效 图…

在版权付费方面,OpenAI 比人想象中的还要「小气」

随着新闻出版商与AI公司达成“使用新闻训练AI模型”的协议&#xff0c;像 OpenAI 等科技企业愿意为受版权保护的信息支付的价格逐渐浮出水面。 据 The Information 报道&#xff0c;OpenAI 每年愿意向出版商提供 100万到500万美元来支付受版权保护的新闻文章训练其AI模型。 但…

【leetcode】力扣热门之合并两个有序列表【简单难度】

题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 用例 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 输入&#xff1a;l1 [], l2 [] 输出&#xff1a;[] 输入&#xff1a;l1 []…

王中阳Go赠书活动第一期:《TVM编译器原理与实践》

文章目录 前言TVM编译器的实现过程关于《TVM编译器原理与实践》编辑推荐内容简介作者简介图书目录书中前言/序言《TVM编译器原理与实践》全书速览入手《TVM编译器原理与实践》传送门&#xff1a;结束语参加抽奖 前言 随着人工智能的发展&#xff0c;计算机视觉、自然语言处理和…

MySQL复习汇总(图书管理系统)

MySQL图书管理系统&#xff08;49-94&#xff09;源码_71.备份book数据库到e盘的mybook.sql文件(备份文件中要求包含建库命令)-CSDN博客 CROSS JOIN&#xff1a;交叉连接&#xff08;笛卡尔积&#xff09; -- 1、 创建一个名称为book的数据库。 -- 2、 打开book数据库…

Vue2-组件的基本应用

个人练习&#xff0c;仅供参考。 1.先在components中创建公用的内容&#xff08;public.vue&#xff09;。components文件夹下放组件供其他页面调用。 2.在用到组件的页面导入该公用组件&#xff08;import navTitle from "/components/public.vue";&#xff09;。 …

linux账户文件/etc/passwd详解

linux 账户文件/etc/passwd Linux 的/etc/passwd 文件是系统中最重要的文件之一&#xff0c;它存储了系统中所有用户的基本信息&#xff0c;包括用户名、密码、用户 ID、组 ID、主目录、登录 shell。 /etc/passwd 文件中的每行记录对应一个用户 每条记录的格式如下&#xff1a…

论文阅读记录SuMa SuMa++

首先是关于SuMa的阅读&#xff0c;SuMa是一个完整的激光SLAM框架&#xff0c;核心在于“基于面元(surfel)”的过程&#xff0c;利用3d点云转换出来的深度图和法向量图来作为输入进行SLAM的过程&#xff0c;此外还改进了后端回环检测的过程&#xff0c;利用提出的面元的概念和使…