Spring IOC - 推断构造方法

一、前言

        上文解析了Bean生命周期的实例化阶段,其中bean真正开始实例化的核心代码位于方法AbstractAutowireCapableBeanFactory#createBeanInstance中,这里也是spring推断构造方法的核心所在。

二、整体介绍

        首先看下方法的源码及注释如下,下面我们再逐行解析。

// 使用适当的实例化策略为指定的bean创建一个新实例:工厂方法、构造函数自动装配或简单实例化
// 创建bean的实例,这里也是spring推断构造方法的核心所在
// args:表示程序员通过getBean传入的参数,如果使用getBean(Class<?> requireType,Object[] args),那么传入的参数就会传入到这里
// 这个参数是用于构造函数或工厂方法调用的显示参数
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.// 获取bean的Class对象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());}// 通过bd中提供的instanceSupplier来获取一个对象// 正常bd中都不会有这个instanceSupplier属性,这里也是Spring提供的一个扩展点,但实际上不常用Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// 如果工厂方法不为null,则使用工厂方法初始化策略// bd中提供了factoryMethodsName属性,那么要使用工厂方法的方法来创建对象// 工厂方法又会区分静态工厂方法跟实例工厂方法if (mbd.getFactoryMethodName() != null) {// 如果使用了工厂方法,则调用工厂方法创建bean实例。@Bean注解创建的实例会进入这里return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...// 在原型模式下,如果已经创建过一次这个Bean了,那么就不需要再次推断构造函数了// 是否推断过构造函数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);}}// 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);
}

        总体流程总结如下:

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

三、Supplier

        Supplier是Spring 用来创建bean的一种方式,但是不常见。即将beanDefiniton属性instanceSupplier设置一个可以返回实例的方法,那么通过该beanDefinition生成实例bean时,会调用Supplier的getObject方法直接返回。示例如下:

public class Analsis {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();beanDefinition.setBeanClass(User.class);beanDefinition.setInstanceSupplier(Teacher::new);beanFactory.registerBeanDefinition("user", beanDefinition);System.out.println(beanFactory.getBean("user"));}
}

        示例返回结果为:com.test.Teacher@6d4b1c02,虽然设置的beanClass属性为User.class,但是返回的bean实例还是Teacher实例。

四、@Bean

        这里阐述的是通过beanDefinition中的factoryMethodName属性来创建bean实例。@Bean标记的方法名就是factoryMethodName,其所在的父类名称就是属性factoryBeanName。通过@Bean标记的实例,其实在解析生成BeanDefinition时,就已经对关键属性进行赋值了,后续的创建过程无非就是根据其属性来实例化,这里有个关键属性:factoryMethodToIntrospect,即通过内省获取的工厂方法,其实到最后就是通过反射机制调用该方法创建实例。

五、推动构造函数

        这里的逻辑是一个扩展点,即调用实现了SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors方法。而AutowiredAnnotationBeanPostProcessor实现了该接口,其源码及注释如下:

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)throws BeanCreationException {// Let's check for lookup methods here...if (!this.lookupMethodsChecked.contains(beanName)) {if (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封装成LookOverride并设置到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);}// Quick check on the concurrent map first, with minimal locking.//决定一组构造方法的逻辑代码,candidateConstructorsCache是一个构造方法候选者的集合,就是说如果找到了符合条件的构造方法//都会缓存到这个集合中,表示是符合条件的构造方法的候选者集合//这里先从缓存中去取,如果缓存中没有,就去推断出符合的记录添加到缓存中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 {//这个是得到一个Bean中的声明的所有的构造方法列表,是一个数组,数组里面是bean中的所有构造方法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);//用来记录@AutoWired标记并且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;}//当前遍历的构造方法是否被@AutoWired注解标记MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);if (ann == null) {//如果beanClass是代理类,则得到被代理类的类型//然后去看被代理类中对应的构造方法是否有@AutoWired注解Class<?> userClass = ClassUtils.getUserClass(beanClass);if (userClass != beanClass) {try {Constructor<?> superCtor =userClass.getDeclaredConstructor(candidate.getParameterTypes());ann = findAutowiredAnnotation(superCtor);}catch (NoSuchMethodException ex) {// Simply proceed, no equivalent superclass constructor found...}}}//当前构造方法加了@AutoWired注解if (ann != null) {//整个类中如果有一个required为true的构造方法,那就不能有其他的加了@Autowired的构造方法if (requiredConstructor != null) {throw new BeanCreationException(beanName,"Invalid autowire-marked constructor: " + candidate +". Found constructor with 'required' Autowired annotation already: " +requiredConstructor);}boolean required = determineRequiredStatus(ann);//required为trueif (required) {//如果已经有@AutoWired注解标注的构造方法,则抛错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);}//如果没有被@AutoWired注解标记,并且是无参的,则赋值给defaultConstructorelse if (candidate.getParameterCount() == 0) {//记录唯一一个无参的构造方法defaultConstructor = candidate;}//从以上代码可以看出,一个类中要么只能有一个required=true的构造方法,要么只能有一个或多个required=false的构造方法}//循环完所有的构造方法//1.candidates要么为空,也就是没有被@Autowired标记的构造方法//2.candidates中只有一个required=true的构造方法//3.candidates中是所有required=false的构造方法//如果candidates不为空,那么就是有@Autowired标记的构造方法if (!candidates.isEmpty()) {// Add default constructor to list of optional constructors, as fallback.//如果不存在一个required=true的构造方法,那么candidates中都是required=false的构造方法if (requiredConstructor == null) {//如果存在无参构造方法将无参构造方法放到candidates中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));}}//1.如果只存在一个required=true的构造方法,那么只有这一个是合格的//2.如果有多个required=false的构造方法,那么所有的required=false的构造方法都是合格的//此时如果有无参构造方法,那么所有required=false和无参构造方法都是合格的candidateConstructors = candidates.toArray(new Constructor<?>[0]);}// 如果没有加了@AutoWired注解的构造方法,并且类中只有一个构造方法,并且该构造方法是有参的,这个构造方法也是合格的else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {candidateConstructors = new Constructor<?>[] {rawCandidates[0]};}// primaryConstructor 不用管kotlinelse if (nonSyntheticConstructors == 2 && primaryConstructor != null &&defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};}// primaryConstructor 不用管kotlinelse 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);
}

        可以得出一个结论:Autowired注解的required属性默认为true,一个类中要么只能有一个required=true的构造方法,要么只能有一个或多个required=false的构造方法,没有标注Autowired的方法可以与他们混合存在。

六、带参实例化

        这里需要对构造函数参数进行解析和推断,从而决定调用哪个构造函数,即通过构造函数参数值去匹配构造函数,其源码和注释,以及逻辑总结如下:

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {//实例化一个beanWrapperImpl类对象BeanWrapperImpl bw = new BeanWrapperImpl();//初始化bw,这里的BeanFactory来自于AbstractAutowireCapableBeanFactorythis.beanFactory.initBeanWrapper(bw);Constructor<?> constructorToUse = null;ArgumentsHolder argsHolderToUse = null;Object[] argsToUse = null;//explicitArgs不为空,说明用户指定了构造方法的参数,直接拿来使用if (explicitArgs != null) {argsToUse = explicitArgs;}else {Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {//尝试从mbd的缓存中拿取构造方法constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;//构造方法不为空并且构造方法已经解析 if (constructorToUse != null && mbd.constructorArgumentsResolved) {// Found a cached constructor...//直接从mbd缓存中拿取构造方法的参数argsToUse = mbd.resolvedConstructorArguments;if (argsToUse == null) {//如果没有拿到构造方法的参数,就获取缓存中的配置文件的参数argsToResolve = mbd.preparedConstructorArguments;}}}if (argsToResolve != null) {//正确拿到配置文件的参数之后,对参数进行解析,最后生成构造方法的参数argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);}}//如果没有拿到构造方法,就说明没有bean进行过解析,需要去关联对应的bean的构造器if (constructorToUse == null || argsToUse == null) {// Take specified constructors, if any.//获取传入的构造器Constructor<?>[] candidates = chosenCtors;//如果构造器不为空if (candidates == null) {//获取bean的类型Class<?> beanClass = mbd.getBeanClass();try {//判断是否允许非公开访问,如果允许就获取所有的构造方法,如果不允许就获取public的构造方法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];//判断这个构造方法的参数个数为0,这个构造方式 就是默认的构造方法if (uniqueCandidate.getParameterCount() == 0) {synchronized (mbd.constructorArgumentLock) {//记录到mbd的缓存中去mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;mbd.constructorArgumentsResolved = true;mbd.resolvedConstructorArguments = EMPTY_ARGS;}//初始化bean, 并且设置到bw(bean 的包装对象)中去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);}//对构造方法进行排序,public的排在前面,参数多的排在前面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);}//isLenientConstructorResolution()判断策略是否宽松//宽松策略下,使用spring构造的参数数组的类型和获取到的构造方法的参数类型进行对比。//严格策略下,还需要检查能否将构造方法的参数复制到对应的属性中//会返回一个数值,作为构造方法和参数的差异值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);}}//用上面得到的构造器和参数来反射创建bean实例,并放到BeanWrapperImpl对象中然后返回Assert.state(argsToUse != null, "Unresolved constructor arguments");bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));return bw;
}

        这个方法的代码量很大,逻辑也比较复杂。我们将逻辑简单拆分,整理成以下几个方面:

1. 构造方法参数值的确定

        1)根据explicitArgs参数判断。

        如果参入的参数explicitArgs不为空,就可以直接确定下参数,因为explicitArgs参数是在调用Bean的时候用户指定的,在BeanFactory类中有这样一个方法:Object getBean(String name, Object... args)

        在获取bean的时候,用户不但可以指定bean的名称还可以指定bean所对应类的构造方法或者工厂方法的参数,主要用于静态工厂方法的调用,这里则是需要给定完全匹配的参数,所以,可以判定explicitArgs不为空,就是构造方法的参数就是它。

        2)缓存中获取

        除此之外,确定参数的办法如果之前已经分析过,构造方法参数已经有记录在缓存中,那么便可以直接拿来使用。但是这里缓存的参数可以是最终的类型也可能是初始的类型。例如:构造方法需要的参数是int类型的1,但是原始参数可能是String类型的“1”,那么即使从缓存中获取到了参数,也需要经过类型转换器来保证与构造方法的参数类型一致。

        3)配置文件获取

        在前两个方法都没法获取到参数的时候,就只能开始新一轮的分析。

从配置文件中获取配置到构造方法的信息开始,经过之前的分析,spring中的配置文件的信息会被转换成通用的BeanDefinition实例,也就是参数mbd,通过调用mbd.getConstructorArgumentValues()来获取配置的构造函数信息。拿到配置中的信息便可以获取到每个参数对应得值。

        4)通过依赖注入获取

        这里涉及到依赖的解析了,在后面文章属性注入详细讲解。

2.构造方法的确定

        经过第一个步之后确定了构造方法的参数,接下来就是要根据构造方法的参数来找到对应的构造方法,匹配的方法就是根据参数的个数对比,在匹配之前需要对构造方法按照public构造方法优先、参数数量降序排列、非public构造方法参数降序排列。这样可以在遍历的情况下迅速的判断出构造方法参数个数是否符合条件。

        由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,还同时支持指定参数名进行设定参数值的情况,如<constructor-arg name="aa">,这种情况下就需要先确定构造方法中的参数名。

        获取参数名可以用两种方式,一种是通用注解的方式直接获取,另一种就是使用Spring中提供的工具类ParameterNameDiscoverer来获取。构造方法、参数名、参数类型、参数值确定之后却可以确定构造方法。

3.根据参数类型转换对应参数的类型。

4.构造函数不确定性验证

        有的时候根据之前的筛选并无法直接确定需要的构造方法,最后根据匹配度做一次验证

5.根据实例化策略以及得到的构造方法参数对bean进行实例化。

七、无参实例化

        这个逻辑就比较简单了,其对应的方法为SimpleInstantiationStrategy#instatance,通过class对象获取参数个数为0的构造方法来实例化。

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

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

相关文章

22款奔驰S450L升级流星雨大灯 感受最高配的数字大灯

“流星雨”数字大灯&#xff0c;极具辨识度&#xff0c;通过260万像素的数字微镜技术&#xff0c;实现“流星雨”仪式感与高度精确的光束分布&#xff1b;在远光灯模式下&#xff0c;光束精准度更达之前84颗LED照明的100倍&#xff0c;更新增坡道照明功能&#xff0c;可根据导航…

2019年12月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 以下程序执行后,角色面向的方向是? A:右上 B:右下 C:左上 D:左下 答案:B 面向-135度,是面向左下角,向右旋转-90度等于向左旋转90度。所以会旋转到右下角。 第2题 以下程…

二十九、W5100S/W5500+RP2040树莓派Pico<Web socket Server>

文章目录 1 前言2 简介2 .1 什么是WebSocket协议&#xff1f;2.2 WebSocket协议工作原理2.3 WebSocket协议优点2.4 WebSocket应用场景 3 WIZnet以太网芯片4 WebSocket示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接…

TCP与UDP协议

TCP与UDP协议 1、TCP协议&#xff1a; 1、TCP特性&#xff1a; TCP 提供一种面向连接的、可靠的字节流服务。在一个 TCP 连接中&#xff0c;仅有两方进行彼此通信。广播和多播不能用于 TCP。TCP 使用校验和&#xff0c;确认和重传机制来保证可靠传输。TCP 给数据分节进行排序…

移动机器人路径规划(四)--- 考虑机器人模型下的运动规划KINODYNAMIC PATHFINDING

目录 1 动力学概念简介 2 State Lattice Planning 3 Boundary Value Problem 4 混合A*算法 Hybrid A* 5 Kinodynamic RRT* 1 动力学概念简介 一种生成机器人的运动同时受限制于运动学的约束&#xff08;避障&#xff09;以及动力学的约束&#xff08;在速度加速度力的约束…

嵌入式QTGit面试题

自己在秋招过程中遇到的QT和嵌入式和Git相关的面试题&#xff0c;因为比较少就一起放了 QT connect第5个参数是什么&#xff1f; Qt::AutoConnection&#xff1a; 默认值&#xff0c;使用这个值则连接类型会在信号发送时决定。 如果接收者和发送者在同一个线程&#xff0c;则…

VSG-001

VulkanSceneGraph (VSG), is a modern, cross platform, high performance scene graph library built upon Vulkan VSG 是一个基于vulkan的现代的、跨平台的高性能场景管理库 VSg特性&#xff1a; 使用C17作为c规范编码&#xff0c;支持 CppCoreGuidelines支持 FOSS Best P…

西南科技大学814考研一

C语言基础 字节大小 char&#xff1a;1 字节 unsigned char&#xff1a;1 字节 short&#xff1a;2 字节 unsigned short&#xff1a;2 字节 int&#xff1a;通常为 4 字节&#xff08;32 位平台&#xff09;或 8 字节&#xff08;64 位平台&#xff09; unsigned int&#x…

go zero手把手教你入门案例

一、入门案例 1、在黑窗口上安装 go install github.com/zeromicro/go-zero/tools/goctllatest2、使用goland创建一个项目 3、在项目中安装依赖 go get -u github.com/zeromicro/go-zerolatest4、模拟创建一个user的项目 goctl api new user5、安装依赖包 go mod tidy6、补充代…

vue项目本地开发完成后部署到服务器后报404

vue项目本地开发完成后部署到服务器后报404是什么原因呢&#xff1f; 一、如何部署 前后端分离开发模式下&#xff0c;前后端是独立布署的&#xff0c;前端只需要将最后的构建物上传至目标服务器的web容器指定的静态目录下即可 我们知道vue项目在构建后&#xff0c;是生成一系…

Guitar Pro2024吉他软件好不好用?

吉他&#xff0c;这把魔幻的弹奏利器&#xff0c;既需要技术&#xff0c;又需要技巧。 是的&#xff0c;它不会自己跳入你的手中&#xff0c;除非你敲对了密码&#xff1a;练习&#xff01; 今天就来看看&#xff0c;大家是不是已经找到了快速掌握吉他的门道呢&#xff1f; …

【DataV可视化工具详解】

文章目录 前言一、什么是DataV&#xff1f;二、主要特点1. 强大的图表库2. 灵活的数据接入3.实时数据展示4. 易于定制的仪表盘 三、应用场景1.业务监控与分析2.大屏展示3.数据洞察与决策支持 四、例图总结我是将军&#xff0c;我一直都在&#xff0c;。&#xff01; 前言 今天…