Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(factoryMethod)

序言

前面文章介绍了在Spring中多种创建Bean实例的方式,包括采用FactoryBean的方式创建对象、使用反射创建对象、自定义BeanFactoryPostProcessor。
这篇文章继续介绍Spring中创建Bean的形式之一——factoryMethod。方法用的不多,感兴趣可以当扩展了解。

doCreateBean

同样是doCreateBean下的createBeanInstance()

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//这个beanWrapper是用来持有创建出来的bean对象的BeanWrapper instanceWrapper = null;//如果是单例对象,从factoryBeanInstanceCache缓存中移除该信息if (mbd.isSingleton()) {// 如果是单例对象,从factoryBean实例缓存中移除当前bean定义信息instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}// 没有就创建实例if (instanceWrapper == null) {// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化instanceWrapper = createBeanInstance(beanName, mbd, args);}// 去除无用代码..... }

createBeanInstance
我们在上篇中介绍了通过Supplier创建Bean的方式,而代码中Supplier判断的下面,就是我们本篇文章要介绍的通过factoryMethod方式创建Bean。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.// 锁定class,根据设置的class属性或者根据className来解析classClass<?> beanClass = resolveBeanClass(mbd, beanName);// 如果beanClass != null// 并且,访问修饰符不是public修饰, 抛异常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());}// 获取定义的SupplierSupplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}return instantiateBean(beanName, mbd);}

测试类
我们这里准备两个测试类,一个是静态工厂的方式,一个是普通的方式进行Bean实例的创建。

PersonStaticFactory
通过静态方法创建Person对象。

public class PersonStaticFactory {public static Person getPerson(String name){Person person = new Person();person.setName(name);person.setAge(22);return person;}
}

PersonInstanceFactory
普通方法创建Bean实例。

public class PersonInstanceFactory {public Person getPerson(String name){Person person = new Person();person.setAge(18);person.setName(name);return person;}
}

Person
平平无奇Person对象。

public class Person {private String name;private int age;// 省略 get  set toString和构造函数
}

factoryMethod.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="personInstanceFactory" class="org.springframework.factoryMethod.PersonInstanceFactory"></bean><bean id="person" class="org.springframework.factoryMethod.PersonStaticFactory" factory-method="getPerson"><constructor-arg name="name" value="zhangsan"/></bean><bean id="person2" class="org.springframework.factoryMethod.Person"factory-bean="personInstanceFactory" factory-method="getPerson"><constructor-arg name="name" value="wangwu"></constructor-arg></bean>
</beans>

main
测试main方法,让我们看看在getBean()中都做了什么操作。

public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("factoryMethod.xml");Person person1 =(Person) ac.getBean("person");Person person2 =(Person)ac.getBean("person2");System.out.println(person1);System.out.println(person2);
}

instantiateUsingFactoryMethod()

方法入口。我们这里以 person2 的创建为例。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.// 锁定class,根据设置的class属性或者根据className来解析classClass<?> beanClass = resolveBeanClass(mbd, beanName);// 如果beanClass != null// 并且,访问修饰符不是public修饰, 抛异常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());}// 获取定义的SupplierSupplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}return instantiateBean(beanName, mbd);}

让我们顺着Supplier的判断顺着往下看。
此时来到了person对象的加载,根据xml文件的配置,此时的beanName所指的person2是Person对象
在这里插入图片描述

创建构造器解析器对象,调用instantiateUsingFactoryMethod()方法进行解析。

protected BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

instantiateUsingFactoryMethod

源码很长,我们这块分段来看。
代码中的第一部分主要是判断当前的BeanDefinition是否包含factoryBeanName,并以此来区分是否是static修饰,并设置标志位。

public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {// 创建 BeanWrapperImpl 对象BeanWrapperImpl bw = new BeanWrapperImpl();//初始化beanWrapper对象,这里面获取了所有的customerEditor进行注册this.beanFactory.initBeanWrapper(bw);Object factoryBean;Class<?> factoryClass;boolean isStatic;//获取factoryBeanNameString factoryBeanName = mbd.getFactoryBeanName();//如果factoryBeanName不为nullif (factoryBeanName != null) {//如果配置的 factoryBeanName与beanName名称相同,则抛出异常if (factoryBeanName.equals(beanName)) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"factory-bean reference points back to the same bean definition");}//从工厂中获取当前factoryBeanName对应的bean对象factoryBean = this.beanFactory.getBean(factoryBeanName);//如果是单例模式,并且容器中已经存在该bean对象,则抛出异常if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {//意味着此时工厂中已经包含了beanName对应的实例对象,再生成则重复了。,抛出异常throw new ImplicitlyAppearedSingletonException();}// 获取factoryBean的Class对象factoryClass = factoryBean.getClass();// 标志位设置为false 表示不是静态方法。isStatic = false;}else {// It's a static factory method on the bean class.// 这是bean类上的静态工厂方法// 如果mbd没有指定bean类if (!mbd.hasBeanClass()) {throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,"bean definition declares neither a bean class nor a factory-bean reference");}factoryBean = null;factoryClass = mbd.getBeanClass();// 标志位设置为 true 表示为静态方法。isStatic = true;}}	

我们这里的person2是普通工厂,并且会在代码this.beanFactory.getBean(factoryBeanName);中通过factoryBeanName来创建我们所配置的PersonInstanceFactory对象。
在这里插入图片描述

声明变量并看调用getBean()方法时是否传了显示的参数。我们这里调用getBean时,什么都没传。所以expliciArgs为null。

		//声明一个要使用的工厂方法,默认为nullMethod factoryMethodToUse = null;//声明一个用于存储不同形式的参数值的ArgumentsHolder,默认为nullArgumentsHolder argsHolderToUse = null;// 声明一个要使用的参数值数组,默认为nullObject[] argsToUse = null;// 如果调用getBean方法时,显示的传了参数,则此时explicitArgs != null// 则argsToUser引用explicitArgsif (explicitArgs != null) {argsToUse = explicitArgs;}else {//如果没有传// 声明一个要解析的args[] , 默认为null。Object[] argsToResolve = null;synchronized (mbd.constructorArgumentLock) {// factoryMethodToUse引用mbd中已经解析构造器或工厂方法对象factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;//如果此时factoryMethodToUse不为null,并且mbd已解析构造函数参数(默认为false)if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {// Found a cached factory method...//找到了缓存工厂方法//argsToUse引用完全解析构的造器函数参数argsToUse = mbd.resolvedConstructorArguments;//如果依然为nullif (argsToUse == null) {//引用mbd准备好的构造函数参数值argsToResolve = mbd.preparedConstructorArguments;}}}//如果argsToResolve不为nullif (argsToResolve != null) {//解析mbd中缓存好的参数值argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);}}

获取所有候选方法并进行过滤。

// 如果没解析过,就获取factoryClass的用户定义类型,因为此时factoryClass可能是CGLIB动态代理类型,// 所以要获取用父类的类型。如果工厂方法是唯一的,就是没重载的,就获取解析的工厂方法,如果不为空,就添加到一个不可变列表里,// 如果为空的话,就要去找出factoryClass的以及父类的所有的方法,进一步找出方法修饰符一致且名字跟工厂方法名字相同的且是bean注解的方法,并放入列表里。if (factoryMethodToUse == null || argsToUse == null) {// Need to determine the factory method...// Try all methods with this name to see if they match the given arguments.// 获取工厂类的所有候选工厂方法factoryClass = ClassUtils.getUserClass(factoryClass);// 定义一个用于存储候选方法的集合List<Method> candidates = null;// 如果mbd所配置工厂方法时唯一if (mbd.isFactoryMethodUnique) {// 如果factoryMethodToUse为nullif (factoryMethodToUse == null) {// 获取mbd解析后的工厂方法对象factoryMethodToUse = mbd.getResolvedFactoryMethod();}// 如果factoryMethodToUse不为nullif (factoryMethodToUse != null) {// Collections.singletonList()返回的是不可变的集合,但是这个长度的集合只有1,可以减少内存空间。但是返回的值依然是Collections的内部实现类,// 同样没有add的方法,调用add,set方法会报错// 新建一个不可变,只能存一个对象的集合,将factoryMethodToUse添加进行,然后让candidateList引用该集合candidates = Collections.singletonList(factoryMethodToUse);}}// 如果candidateList为nullif (candidates == null) {// 让candidateList引用一个新的ArrayListcandidates = new ArrayList<>();// 根据mbd的是否允许访问非公共构造函数和方法标记【RootBeanDefinition.isNonPublicAccessAllowed】来获取factoryClass的所有候选方法Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);// 遍历rawCandidates,元素名为candidatefor (Method candidate : rawCandidates) {// 如果candidate的修饰符与isStatic一致且candidate有资格作为mdb的工厂方法if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {// 将candidate添加到candidateList中candidates.add(candidate);}}}// 候选方法只有一个且没有构造函数时,就直接使用该候选方法生成与beanName对应的Bean对象封装到bw中返回出去// 如果candidateList只有一个元素且没有传入构造函数值且mbd也没有构造函数参数值if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {// 获取candidateList中唯一的方法Method uniqueCandidate = candidates.get(0);// 如果uniqueCandidate是不需要参数if (uniqueCandidate.getParameterCount() == 0) {// 让mbd缓存uniqueCandidate【{@link RootBeanDefinition#factoryMethodToIntrospect}】mbd.factoryMethodToIntrospect = uniqueCandidate;// 使用mdb的构造函数字段的通用锁【{@link RootBeanDefinition#constructorArgumentLock}】进行加锁以保证线程安全synchronized (mbd.constructorArgumentLock) {// 让mbd缓存已解析的构造函数或工厂方法【{@link RootBeanDefinition#resolvedConstructorOrFactoryMethod}】mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;// 让mbd标记构造函数参数已解析【{@link RootBeanDefinition#constructorArgumentsResolved}】mbd.constructorArgumentsResolved = true;// 让mbd缓存完全解析的构造函数参数【{@link RootBeanDefinition#resolvedConstructorArguments}】mbd.resolvedConstructorArguments = EMPTY_ARGS;}// 使用factoryBean生成的与beanName对应的Bean对象,并将该Bean对象保存到bw中bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));// 将bw返回出去return bw;}}// 如果有多个工厂方法的话进行排序操作if (candidates.size() > 1) {  // explicitly skip immutable singletonListcandidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);}

因为所有的对象的父类都是Object,所以会获取很多Object中的方法,经过过滤后,这里candidates只保留了getPerson()
在这里插入图片描述
过滤后,只剩getPerson()方法。
在这里插入图片描述
根据candidate数量,如果只有一个且符合条件,则进行对象的创建,如果有多个则进行排序。
如果有构造函数,则获取构造函数的属性和值。

			// 候选方法只有一个且没有构造函数时,就直接使用该候选方法生成与beanName对应的Bean对象封装到bw中返回出去// 如果candidateList只有一个元素且没有传入构造函数值且mbd也没有构造函数参数值if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {// 获取candidateList中唯一的方法Method uniqueCandidate = candidates.get(0);// 如果uniqueCandidate是不需要参数if (uniqueCandidate.getParameterCount() == 0) {// 让mbd缓存uniqueCandidate【{@link RootBeanDefinition#factoryMethodToIntrospect}】mbd.factoryMethodToIntrospect = uniqueCandidate;// 使用mdb的构造函数字段的通用锁【{@link RootBeanDefinition#constructorArgumentLock}】进行加锁以保证线程安全synchronized (mbd.constructorArgumentLock) {// 让mbd缓存已解析的构造函数或工厂方法【{@link RootBeanDefinition#resolvedConstructorOrFactoryMethod}】mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;// 让mbd标记构造函数参数已解析【{@link RootBeanDefinition#constructorArgumentsResolved}】mbd.constructorArgumentsResolved = true;// 让mbd缓存完全解析的构造函数参数【{@link RootBeanDefinition#resolvedConstructorArguments}】mbd.resolvedConstructorArguments = EMPTY_ARGS;}// 使用factoryBean生成的与beanName对应的Bean对象,并将该Bean对象保存到bw中bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));// 将bw返回出去return bw;}}// 如果有多个工厂方法的话进行排序操作if (candidates.size() > 1) {  // explicitly skip immutable singletonListcandidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);}// ConstructorArgumentValues:构造函数参数值的Holder,通常作为BeanDefinition的一部分,支持构造函数参数列表中特定索引的值// 以及按类型的通用参数匹配// 定义一个用于存放解析后的构造函数参数值的ConstructorArgumentValues对象ConstructorArgumentValues resolvedValues = null;// 定义一个mbd是否支持使用构造函数进行自动注入的标记boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);// 定义一个最小类型差异权重,默认是Integer最大值int minTypeDiffWeight = Integer.MAX_VALUE;// 定义一个存储摸棱两可的工厂方法的Set集合,以用于抛出BeanCreationException时描述异常信息Set<Method> ambiguousFactoryMethods = null;// 定义一个最少参数数,默认为0int minNrOfArgs;// 如果explicitArgs不为nullif (explicitArgs != null) {// minNrOfArgs引用explicitArgs的数组长度minNrOfArgs = explicitArgs.length;}else {// We don't have arguments passed in programmatically, so we need to resolve the// arguments specified in the constructor arguments held in the bean definition.// 我们没有以编程方式传递参数,因此我们需要解析BeanDefinition中保存的构造函数参数中指定的参数// 如果mbd有构造函数参数值if (mbd.hasConstructorArgumentValues()) {// 获取mbd的构造函数参数值HolderConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();// 对resolvedValues实例化resolvedValues = new ConstructorArgumentValues();// 将cargs解析后值保存到resolveValues中,并让minNrOfArgs引用解析后的最小(索引参数值数+泛型参数值数)minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}else {// 意味着mbd没有构造函数参数值时,将minNrOfArgs设为0minNrOfArgs = 0;}}

获取构造函数的属性和值。
在这里插入图片描述
获取参数列表并进行封装。

	// 定义一个用于UnsatisfiedDependencyException的列表LinkedList<UnsatisfiedDependencyException> causes = null;// 遍历candidates,元素名为candidatefor (Method candidate : candidates) {// 获取参数的个数int parameterCount = candidate.getParameterCount();// 如果paramTypes的数组长度大于等于minNrOfArgsif (parameterCount >= minNrOfArgs) {// ArgumentsHolder:用于保存参数数组// 定义一个封装参数数组的ArgumentsHolder对象ArgumentsHolder argsHolder;// 获取candidate的参数类型数组Class<?>[] paramTypes = candidate.getParameterTypes();// 如果explicitArgs不为nullif (explicitArgs != null) {// Explicit arguments given -> arguments length must match exactly.// 给定的显示参数->参数长度必须完全匹配// 如果paramTypes的长度与explicitArgsd额长度不相等if (paramTypes.length != explicitArgs.length) {// 跳过当次循环中剩下的步骤,执行下一次循环。continue;}// 实例化argsHolder,封装explicitArgs到argsHolderargsHolder = new ArgumentsHolder(explicitArgs);}else {// Resolved constructor arguments: type conversion and/or autowiring necessary.// 已解析的构造函数参数:类型转换 and/or 自动注入时必须的try {// 定义用于保存参数名的数组String[] paramNames = null;// 获取beanFactory的参数名发现器ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();// 如果pnd不为nullif (pnd != null) {// 通过pnd解析candidate的参数名paramNames = pnd.getParameterNames(candidate);}// 将resolvedValues转换成一个封装着参数数组ArgumentsHolder实例,当candidate只有一个时,支持可在抛// 出没有此类BeanDefinition的异常返回null,而不抛出异常argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);}// 捕捉UnsatisfiedDependencyExceptioncatch (UnsatisfiedDependencyException ex) {if (logger.isTraceEnabled()) {logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);}// Swallow and try next overloaded factory method.// 吞下并尝试下一个重载的工厂方法// 如果cause为nullif (causes == null) {// 对cause进行实例化成LinkedList对象causes = new LinkedList<>();}// 将ex添加到causes中causes.add(ex);// 跳过本次循环体中余下尚未执行的语句,立即进行下一次的循环continue;}}

Spring会计算权重,选出符合条件的方法来进行实例对象的创建。

				// mbd支持的构造函数解析模式,默认使用宽松模式:// 1. 严格模式如果摸棱两可的构造函数在转换参数时都匹配,则抛出异常// 2. 宽松模式将使用"最接近类型匹配"的构造函数// 如果bd支持的构造函数解析模式时宽松模式,引用获取类型差异权重值,否则引用获取Assignabliity权重值int typeDiffWeight = (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this factory method if it represents the closest match.// 如果它表示最接近的匹配项,则选择此工厂方法// 如果typeDiffWeight小于minTypeDiffWeightif (typeDiffWeight < minTypeDiffWeight) {// 让factoryMethodToUser引用candidatefactoryMethodToUse = candidate;// 让argsHolderToUse引用argsHolderargsHolderToUse = argsHolder;// 让argToUse引用argsHolder的经过转换后参数值数组argsToUse = argsHolder.arguments;// 让minTypeDiffWeight引用typeDiffWeightminTypeDiffWeight = typeDiffWeight;// 将ambiguousFactoryMethods置为nullambiguousFactoryMethods = null;}// Find out about ambiguity: In case of the same type difference weight// for methods with the same number of parameters, collect such candidates// and eventually raise an ambiguity exception.// However, only perform that check in non-lenient constructor resolution mode,// and explicitly ignore overridden methods (with the same parameter signature).// 找出歧义:如果具有相同数量参数的方法具有相同的类型差异权重,则收集此类候选想并最终引发歧义异常。// 但是,仅在非宽松构造函数解析模式下执行该检查,并显示忽略的方法(具有相同的参数签名)// 如果factoryMethodToUse不为null且typeDiffWeight与minTypeDiffWeight相等// 且mbd指定了严格模式解析构造函数且paramTypes的数组长度与factoryMethodToUse的参数数组长度相等且// paramTypes的数组元素与factoryMethodToUse的参数数组元素不相等else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&!mbd.isLenientConstructorResolution() &&paramTypes.length == factoryMethodToUse.getParameterCount() &&!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {// 如果ambiguousFactoryMethods为nullif (ambiguousFactoryMethods == null) {// 初始化ambiguousFactoryMethods为LinkedHashSet实例ambiguousFactoryMethods = new LinkedHashSet<>();// 将factoryMethodToUse添加到ambiguousFactoryMethods中ambiguousFactoryMethods.add(factoryMethodToUse);}// 将candidate添加到ambiguousFactoryMethods中ambiguousFactoryMethods.add(candidate);}}}// 整合无法筛选出候选方法或者无法解析出要使用的参数值的情况,抛出BeanCreationException并加以描述// 如果factoryMethodToUse为null或者argsToUse为nullif (factoryMethodToUse == null || argsToUse == null) {// 如果causes不为nullif (causes != null) {// 从cause中移除最新的UnsatisfiedDependencyExceptionUnsatisfiedDependencyException ex = causes.removeLast();// 遍历causes,元素为causefor (Exception cause : causes) {// 将cause添加到该Bean工厂的抑制异常列表【{@link DefaultSingletonBeanRegistry#suppressedExceptions】中this.beanFactory.onSuppressedException(cause);}// 重新抛出exthrow ex;}// 定义一个用于存放参数类型的简单类名的ArrayList对象,长度为minNrOfArgsList<String> argTypes = new ArrayList<>(minNrOfArgs);// 如果explicitArgs不为nullif (explicitArgs != null) {// 遍历explicitArgs.元素为argfor (Object arg : explicitArgs) {// 如果arg不为null,将arg的简单类名添加到argTypes中;否则将"null"添加到argTypes中argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");}}// 如果resolvedValues不为nullelse if (resolvedValues != null) {// 定义一个用于存放resolvedValues的泛型参数值和方法参数值的LinkedHashSet对象Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());// 将resolvedValues的方法参数值添加到valueHolders中valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());// 将resolvedValues的泛型参数值添加到valueHolders中valueHolders.addAll(resolvedValues.getGenericArgumentValues());// 遍历valueHolders,元素为valuefor (ValueHolder value : valueHolders) {// 如果value的参数类型不为null,就获取该参数类型的简单类名;否则(如果value的参数值不为null,即获取该参数值的简单类名;否则为"null")String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));// 将argType添加到argTypes中argTypes.add(argType);}}// 将argType转换成字符串,以","隔开元素.用于描述Bean创建异常String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);// 抛出BeanCreationException:找不到匹配的工厂方法:工厂Bean'mbd.getFactoryBeanName()';工厂方法// 'mbd.getFactoryMethodName()(argDesc)'.检查是否存在具体指定名称和参数的方法,并且该方法时静态/非静态的.throw new BeanCreationException(mbd.getResourceDescription(), beanName,"No matching factory method found: " +(mbd.getFactoryBeanName() != null ?"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +"Check that a method with the specified name " +(minNrOfArgs > 0 ? "and arguments " : "") +"exists and that it is " +(isStatic ? "static" : "non-static") + ".");}// 如果factoryMethodToUse时无返回值方法else if (void.class == factoryMethodToUse.getReturnType()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Invalid factory method '" + mbd.getFactoryMethodName() +"': needs to have a non-void return type!");}// 如果ambiguousFactoryMethods不为nullelse if (ambiguousFactoryMethods != null) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Ambiguous factory method matches found in bean '" + beanName + "' " +"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +ambiguousFactoryMethods);}// 将筛选出来的工厂方法和解析出来的参数值缓存到mdb中// 如果explicitArgs为null且argsHolderToUser不为nullif (explicitArgs == null && argsHolderToUse != null) {// 让mbd的唯一方法候选【{@link RootBeanDefinition#factoryMethodToIntrospect}】引用factoryMethodToUsembd.factoryMethodToIntrospect = factoryMethodToUse;// 将argsHolderToUse所得到的参数值属性缓存到mbd对应的属性中argsHolderToUse.storeCache(mbd, factoryMethodToUse);}}// 使用factoryBean生成与beanName对应的Bean对象,并将该Bean对象保存到bw中bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));// 将bw返回出去return bw;

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

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

相关文章

【Git】--Part3--远程操作 配置 标签管理

1. 远程仓库 Git 是分布式版本控制系统&#xff0c;同⼀个 Git 仓库&#xff0c;可以分布到不同的机器上。怎么分布呢&#xff1f; 最早&#xff0c;肯定只有⼀台机器有⼀个原始版本库&#xff0c;此后&#xff0c;别的机器可以 “克隆” 这个原始版本库&#xff0c;⽽且每台机…

JEnv-for-Windows 详细使用

管理员执行jenv.bat文件 执行正常, 接下来就是按照官网的命令就行了 文件下载地址 https://download.csdn.net/download/qq_43071699/89462664 JEnv 是一个强大的Java版本管理工具&#xff0c;允许开发者在多个Java版本之间轻松切换。以下是一些常用的JEnv命令&#xff0c;这…

118 杨辉三角

题目 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 解析 就是模拟法&#xff0c;没有什么特殊的…

一文教你在centos 7.9中安装mysql5.7(超级详细)

##red## &#x1f534; 大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff0c;雄雄的小课堂。 一、前言 每当新来一个服务器之后&#xff0c;习惯性的都会安装一个宝塔面板&#xff0c;不为别的&#xff0c;就为了装环境方便点儿&#xff0c;比如常用的jdk,m…

C++学习(23)

#学习自用# union 共用体和结构体相似&#xff0c;但是共用体一次只能占用一个成员的内存&#xff0c;所有成员共用同一地址。 #include<iostream> using namespace std; union A {int int_val;float float_val; }a; int main() {a.float_val 2.0f;cout << a.f…

【免费API推荐】:解锁无限创意,让您的应用更具竞争力(8)

热门高效的免费实用类API是当今开发者们追逐的宝藏。这些API提供了各种热门功能和服务&#xff0c;能够帮助开发者轻松地为应用程序增添实用性和吸引力。无论是人脸识别、自然语言处理、机器学习还是图像处理&#xff0c;这些热门高效的免费API提供了强大的功能和高效的性能&am…

vuejs3+elementPlus后台管理系统,左侧菜单栏制作、跳转、默认激活菜单

制作&#xff1a; <script setup> import {useUserStore} from "/stores/userStore.js"; import {ref} from "vue";const userStore useUserStore() //默认激活菜单 const defaultMenu ref(/home) </script><template><el-menuact…

Redis 主从复制+哨兵+集群

Redis复制 查看docker 容器 ip docker inspect 容器id | grep IPAddressdocker inspect -f{{.Name}} {{.NetworkSettings.IPAddress}} $(docker ps -aq)修改配置文件 初始配置文件见 > redis.conf 远程访问 bind 0.0.0.0protected-mode no 主机设置 replicaof 172.17.0.…

Vue66-vue-默认插槽

一、默认插槽需求 1-1、原本的写法&#xff1a; 在每个category组件中用v-show来做条件渲染&#xff0c;但是不方便&#xff01; 1-2、默认插槽 img标签&#xff0c;ul标签&#xff0c;video标签&#xff0c;都是在app组件中完成解析之后&#xff0c;塞到category组件中的&…

汉朔科技IPO:引领智慧零售新时代,推动行业数字化转型

汉朔科技是一家以物联网无线通信技术为核心的高新技术企业&#xff0c;围绕零售门店数字化领域&#xff0c;构建了以电子价签系统、SaaS云平台服务等软硬件产品及服务为核心的业务体系。凭借公司技术实力、战略布局和多年行业积累&#xff0c;汉朔科技成为了零售门店数字化解决…

蓝鹏测控公司全长直线度算法项目多部门现场组织验收

关键字:全场直线度算法,直线度测量仪,直线度检测,直线度测量设备, 6月18日上午&#xff0c;蓝鹏测控公司全长直线度算法项目顺利通过多部门现场验收。该项目由公司技术部、开发部、生产部等多个部门共同参与&#xff0c;旨在提高直线度测量精度&#xff0c;满足高精度制造领域需…

Redis分片集群搭建

主从模式可以解决高可用、高并发读的问题。但依然有两个问题没有解决&#xff1a; 海量数据存储高并发写 要解决这两个问题就需要用到分片集群了。分片的意思&#xff0c;就是把数据拆分存储到不同节点&#xff0c;这样整个集群的存储数据量就更大了。 Redis分片集群的结构如…

LVGL使用GUI Guider配置STM32界面详细笔记教程

0、说明 接着前面几篇博客对LVGL的使用和介绍&#xff0c;这篇博客主要是使用和介绍快速配置LVGL图形界面编程的工具&#xff0c;GUI Guider。本文使用的工程代码&#xff0c;均是基于前几篇博客的基础上的&#xff0c;如需下载已配置好的LVGL-MCU工程环境&#xff0c;可通过如…

【R语言】对一个Plot绘制多个图,并且每个图单元也包含多个图

以一个Plot绘制五行六列共30个图&#xff0c;然后每30个图单元包含两个图为例&#xff1a; 如下图所示&#xff1a; 代码如下&#xff1a; for (i in 1:(5*6)) {create_subplots <- function() {library(ggplot2)library(dplyr)library(tidyr)# 创建一个随机的数据框simula…

【机器学习】机器学习重要方法—— 半监督学习:理论、算法与实践

文章目录 引言第一章 半监督学习的基本概念1.1 什么是半监督学习1.2 半监督学习的优势 第二章 半监督学习的核心算法2.1 自训练&#xff08;Self-Training&#xff09;2.2 协同训练&#xff08;Co-Training&#xff09;2.3 图半监督学习&#xff08;Graph-Based Semi-Supervise…

【服务器04】之【Navicat连接阿里云】

通过前三篇文章&#xff0c;现在我们测试可以连接数据库了 点开桌面的 接下找来的主机 地址在以下 登录阿里云 登陆账号后 点击控制台 输入RDS 弹出新页面&#xff0c;并点击运行中的 1 点管理 复制外网地址 鼠标靠近就会出现复制图标 用户名 和 密码 是注册阿里云的高权限账…

对错问题:凡事没有绝对的对与错,要看义所在、良知所在

孔子说&#xff1a;君子对于天下所发生的很多事&#xff0c;如评判政策变动、战争等&#xff0c;没有绝对的对&#xff0c;也没有绝对的错&#xff0c;一切要看事情本身是否符合“ 义 ”。

实验2:RIPv2的配置

由于RIPv1是有类别的路由协议,路由更新不携带子网信息,不支持不连续子网、VLSM、手工汇总和验证等&#xff0c;本书重点讨论RIPv2。 1、实验目的 通过本实验可以掌握&#xff1a; RIPv1和 RIPv2的区别。在路由器上启动RIPv2路由进程。激活参与RIPv2路由协议的接口。auto-sum…

SpringSecurity实战入门——认证

项目代码 gson/spring-security-demo 简介 Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。 一般来说中大型的项目都是使用SpringSecurity来做安全框架。小项目有Shiro的比较多,因为相比…

WordPress管理员后台登录地址修改教程,WordPress admin登录地址文件修改方法

我们使用WordPress时&#xff0c;管理员后台登录默认地址为“域名/wp-login.php”或“域名/wp-admin”&#xff0c;为了安全&#xff0c;一般会把此地址改掉&#xff0c;防止有人恶意来攻击咱的WordPress&#xff0c;今天出个WordPress后台登录地址修改教程&#xff0c;修改之后…