做外贸电商网站有哪个,怎么自己改自己做的网站的图片,网页美工设计培训学什么,wordpress百度云伪静态Spring中bean虽然可以通过多种方式#xff08;Supplier接口、FactoryMethod、构造器#xff09;创建bean的实例对象#xff0c;但是使用最多的还是通过构造器创建对象实例#xff0c;也是我们最熟悉的创建对象的方式。如果有多个构造器时#xff0c;那Spring是如何推断使用… Spring中bean虽然可以通过多种方式Supplier接口、FactoryMethod、构造器创建bean的实例对象但是使用最多的还是通过构造器创建对象实例也是我们最熟悉的创建对象的方式。如果有多个构造器时那Spring是如何推断使用哪个构造器来创建bean对象实例的
一、Spring中创建对象实例的方式
1 通过构造器实例化对象 这是我们创建实例最常使用的方式也是最常见的方式。
public class ObjectInstance {private String createMode;public ObjectInstance(String createMode) {System.out.println(create by constructor);this.createMode createMode;}public ObjectInstance() {}public String getCreateMode() {return createMode;}public void setCreateMode(String createMode) {this.createMode createMode;}Overridepublic String toString() {return ObjectInstance{ createMode createMode \ };}
}
!--通过构造器实例化bean--bean idobjBean classcn.crazy.newInstance.ObjectInstanceconstructor-arg namecreateMode valuecreate by constructor/constructor-arg/bean
2通过工厂方法实例化对象
public class CrazyInstanceFactory {//静态工厂方法public static Object newInstanceForStatic(){ObjectInstance objectInstance new ObjectInstance();objectInstance.setCreateMode(create by factorys static method);return objectInstance;}//实例工厂方法public Object newInstance(){ObjectInstance objectInstance new ObjectInstance();objectInstance.setCreateMode(create by factorys instance method);return objectInstance;}
} i静态工厂方法
!--通过静态工厂实例化bean--bean idobjInstanceForStaticFactory classcn.crazy.newInstance.CrazyInstanceFactory factory-methodnewInstanceForStatic/bean ii实例工厂方法
!--通过实例工厂实例化bean--bean idcrazyInstanceFactory classcn.crazy.newInstance.CrazyInstanceFactory/beanbean idobjInstance factory-beancrazyInstanceFactory factory-methodnewInstance/bean
3通过实现FactoryBean接口实例化对象
public class CrazyFactoryBean implements FactoryBeanObjectInstance {Overridepublic ObjectInstance getObject() throws Exception {ObjectInstance objectInstance new ObjectInstance();objectInstance.setCreateMode(create by FactoryBean);return objectInstance;}Overridepublic Class? getObjectType() {return null;}Overridepublic boolean isSingleton() {return true;}
}
!--通过FactoryBean接口实例化bean--bean idobjInstanceForFactoryBean classcn.crazy.newInstance.CrazyFactoryBean/bean
4通过Supplier实例化对象
public class SupplierObj{private String version;private int num;public SupplierObj() {}public String getVersion() {return version;}public void setVersion(String version) {this.version version;}public int getNum() {return num;}public void setNum(int num) {this.num num;}Overridepublic String toString() {return SupplierObj{ version version \ , num num };}
} 使用BeanFactoryPostProcessor对beanDefinition信息进行修改为其通过一个Supplier,用于实例化bean。 Supplier接口只有一个方法我们可以用简化语法创建匿名接口实现类。
FunctionalInterface
public interface SupplierT {/*** Gets a result.** return a result*/T get();
}
public class MyPostProcessor implements BeanFactoryPostProcessor {Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {GenericBeanDefinition beanDefinition (GenericBeanDefinition)beanFactory.getBeanDefinition(supplierObj);//beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue();beanDefinition.setInstanceSupplier(() - {SupplierObj supplierObj1 new SupplierObj();return supplierObj1;});}
}
bean idsupplierObj classcn.crazy.newInstance.SupplierObjproperty namenum value12/propertyproperty nameversion value1.0.0/property/bean
二、推断构造器
1doCreateBean()创建bean实例对象。 doCreateBean()方法是Spring进行Bean创建的核心方法它包含三个参数
String beanName,就是bean的id或anmeRootBeanDefinition mbdSpring Bean在没有被创建之前bean的信息xml配置bean及注解注入的信息会被解析成BeanDefinition对象我们知道Class是描述Java对象信息的,那么BeanDefinition就是描述Spring Bean信息的Object[] args构造器参数。这个值默认为null除非程序员自己调用api传入参数。 这个方法中会调用多次后置处理器用于推断构造器、完成BD合并、解决循环依赖、解析注解等。我们今天主要看关于自动装配相关的内容所以给这个方法省略了一些内容。 首先是推断构造器通过合适的构造器创建bean的实例然后对实例进行属性填充。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper null;if (mbd.isSingleton()) {instanceWrapper this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper null) {//第二次调用后置处理器的入口方法推断构造方法//代码块一创建实例beaninstanceWrapper createBeanInstance(beanName, mbd, args);}……//填充属性//调用第五次和第六次后置处理器的地方populateBean(beanName, mbd, instanceWrapper);return exposedObject;} 2 createBeanInstance()根据特定的bean及实例化策略创建一个bean实例。 实例化一个bean的方式包括Supplier接口、FactoryMethod、构造器等。 spring会缓存一些关于对象创建中比较复杂的操作方便在原型下bean创建可以直接获取到对象创建的方式而不是又进行复杂的推断。 resolved表示创建对象的构造方法有没有被解析过 。为什么要有这个标签 方便spring快速的创建对象 因为创建对象时推断构造方法是个很复杂的过程在创建原型bean时可以只推断一次后续不用在执行这个复杂的操作 。
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);//判断beanClass是否不符合要求if (beanClass ! null !Modifier.isPublic(beanClass.getModifiers()) !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,Bean class isnt public, and non-public access not allowed: beanClass.getName());}//这段代码的含义是spring提供了一个Supplier接口用于实例化beanSupplier? instanceSupplier mbd.getInstanceSupplier();if (instanceSupplier ! null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() ! null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// Shortcut when re-creating the same bean...//resolved表示创建对象的构造方法有没有被解析过/*** 为什么要有这个标签* 方便spring快速的创建对象* 因为创建对象时推断构造方法是个很复杂的过程在创建原型bean时可以只推断一次后续不用在执行这个复杂的操作*/boolean resolved false;//构造函数参数是否被解析过boolean autowireNecessary false;//args是goGetBean(……,args,……)的入参spring自身传入为nullif (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);}}//推断构造方法有多个构造方法是推断出最合适的如果只有一个构造方法返回null不用推断// 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);} 3代码块二determineCandidateConstructors()推断构造器 推断构造器是通过一个后置处理器AutowiredAnnotationBeanPostProcessor来完成的这个后置处理器是Spring启动时自添加的。
OverrideNullablepublic Constructor?[] determineCandidateConstructors(Class? beanClass, final String beanName)throws BeanCreationException {// 省略lookup methods检查//先从缓存中拿拿不到再进行推断// Quick check on the concurrent map first, with minimal locking.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 {//getDeclared拿到所有类型的public、protected、private,但不会拿父类的//拿到所有的构造器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);}ListConstructor? candidates new ArrayList(rawCandidates.length);Constructor? requiredConstructor null;Constructor? defaultConstructor null;//没有使用到kotlin时永远返回nullConstructor? primaryConstructor BeanUtils.findPrimaryConstructor(beanClass);int nonSyntheticConstructors 0;for (Constructor? candidate : rawCandidates) {if (!candidate.isSynthetic()) {nonSyntheticConstructors;}else if (primaryConstructor ! null) {continue;}MergedAnnotation? ann findAutowiredAnnotation(candidate);if (ann null) {//beanClass是个CGLIB代理类找到父类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...}}}if (ann ! null) {//已经有Autowired(requiredtrue)标记的构造器时如果再出现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);if (required) {//有多个加了构造器Autowired或Value注解if (!candidates.isEmpty()) {throw new BeanCreationException(beanName,Invalid autowire-marked constructors: candidates . Found constructor with required Autowired annotation: candidate);}//Autowired(requiredtrue)的构造器才会设置为requiredConstructorrequiredConstructor candidate;}//只有添加了构造方法上加了Autowired或Value注解该构造方法都会放入candidatescandidates.add(candidate);}else if (candidate.getParameterCount() 0) {//defaultConstructor设置为无参构造器defaultConstructor candidate;}}if (!candidates.isEmpty()) {// Add default constructor to list of optional constructors, as fallback.if (requiredConstructor null) {if (defaultConstructor ! null) {//如果candidates不能空且无确定的构造方法添加默认的构造方法到可选列表中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));}}//将candidates转换为构造器数组candidateConstructors candidates.toArray(new Constructor?[0]);}//仅当一个有参构造方法时才会返回这个构造方法else if (rawCandidates.length 1 rawCandidates[0].getParameterCount() 0) {candidateConstructors new Constructor?[] {rawCandidates[0]};}// primaryConstructor永远为nullelse 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);}
这个方法大致总结为
1先从缓存中获取候选构造器数组 如果能获取成功判断数组长度是否大于0大于0则返回这个构造器数组否则返回null。不存在缓存则进行步骤2。
2获取beanClass中的所有类型的构造器public、protected、private存放到rawCandidates数组。创建一个存放候选构造器的List集合candidates长度为 rawCandidates数组的长度创建三个构造器类型的变量requiredConstructor存储Autowired(required true)标记的构造器、defaultConstructor存储默认的构造器和primaryConstructor没有使用到kotlin时永远返回null
创建一个int类型的变量nonSyntheticConstructors用于记录beanClass非合成构造器的个数。
3遍历rawCandidates数组如果当前的构造器对象为非合成构造器nonSyntheticConstructors计数器1。定义一个MergedAnnotation类型变量ann,存放当前构造器的Autowired注解信息如果当前beanClass的ann为null判断beanClass是否为CGLIB代理类如果是将父类相同参数类型相同构造器上的Autowired注解信息赋值给ann。 a如果注解信息ann不为null i判断requiredConstructor是否为null如果不为null说明beanClass中已经存在一个Autowired(requiredtrue)的构造器抛出异常 ii获取当前构造器上的注解信息ann的required属性值如果为true如果候选构造器的List集合candidates不为空抛出异常。否则将当前构造器赋值给requiredConstructor变量。 iii将当前构造器加入到候选构造器的List集合candidates中。 b) 如果注解信息ann为null 如果当前构造器为无参构造器将当前构造器赋值给defaultConstructor变量。
4完成遍历后有如下几种情况 acandidates不为空的情况如果requiredConstructor为nulldefaultConstructor不为null将defaultConstructor加入候选构造器集合candidates中。将candidates转换为构造器数组对象。
brawCandidates数组长度为1且其中的构造器参数个数大于0仅当一个有参构造方法时才会返回这个构造方法将这个构造器对象封装成构造器数组对象。
cnonSyntheticConstructors2beanClass只有两个非合成构造器且primaryConstructor不为null(没有使用到kotlin时永远返回null)将primaryConstructor和defaultConstructor封装成构造器数组对象。 dnonSyntheticConstructors1且primaryConstructor不为null(没有使用到kotlin时永远返回null)将primaryConstructorr封装成构造器数组对象。 e不是以上情况返回空构造器数组对象。
5将构造器数组对象缓存到spring容器中并返回这个数组对象。 3代码块三autowireConstructor()确定构造器及构造器方法参数的值完成对象实例化。 通过推断构造器方法只是推断出合适的构造器但是可能存在多个候选构造器的情况而且构造器的参数值也还没有确定接下来就是确定构造方法参数的值并完成对象的实例化。
{
……
Constructor?[] ctors determineConstructorsFromBeanPostProcessors(beanClass, beanName);//如果自动注入的方式为构造器注入会再一次推断构造方法if (ctors ! null || mbd.getResolvedAutowireMode() AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {//确定构造方法参数的值return autowireConstructor(beanName, mbd, ctors, args);}……
}protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, Nullable Constructor?[] ctors, Nullable Object[] explicitArgs) {return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);}
//这里只是简单初始化
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {this.beanFactory beanFactory;this.logger beanFactory.getLogger();} 这里定义了很多中间变量如
//最终使用的构造方法
Constructor? constructorToUse null;
//最终使用的参数持有者维护了参数差异值比较的方法
ArgumentsHolder argsHolderToUse null;
//最终使用的构造方法参数
Object[] argsToUse null;
//这个值默认为null除非程序员自己调用api传入参数
//createBean(beanName, mbd, args);中args即是explicitArgs
Object[] explicitArgs;
//解析出来的构造器参数值
//解析出来的参数不一定就是可以直接注入的属性需要进行转换
//如constructor-arg type /constructor-arg或如constructor-arg ref /constructor-arg
//需要转换成具体的Bean才能注入
Object[] argsToResolve null;
//最小参数个数,如果手动设置构造器参数createBean(beanName, mbd, args)或
//xml配置了constructor-arg/constructor-arg
//或设置了BeanDefinition.getConstructorArgumentValues().addArgumentValues();
//最小参数个数就是设置参数的个数
int minNrOfArgs;
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;//构造器参数。这个值默认为null除非程序员自己调用api传入参数//createBean(beanName, mbd, args);中args即是explicitArgsif (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) {//构造器中没有缓存构造参数就需要获取preparedConstructorArguments//部分准备好的构造函数参数不是最终使用的构造器参数需要转换argsToResolve mbd.preparedConstructorArguments;}}}if (argsToResolve ! null) {//解析出来的参数不一定就是可以直接注入的属性需要进行转换//如constructor-arg type /constructor-arg或如constructor-arg ref /constructor-arg//需要转换成具体的Bean才能注入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 {//拿出所有的构造方法// mbd.isNonPublicAccessAllowed() true是否允许非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];//无参构造器if (uniqueCandidate.getParameterCount() 0) {//设置缓存synchronized (mbd.constructorArgumentLock) {mbd.resolvedConstructorOrFactoryMethod uniqueCandidate;mbd.constructorArgumentsResolved true;mbd.resolvedConstructorArguments EMPTY_ARGS;}//通过无参构造器实例化beanbw.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;//实际传入构造方法参数个数不为nullif (explicitArgs ! null) {//如果指定了构造器参数值最小参数个数为指定的参数个数minNrOfArgs explicitArgs.length;}else {//xml配置了constructor-arg/constructor-arg//或设置了BeanDefinition.getConstructorArgumentValues().addArgumentValues();//就根据手动设置的构造器参数推断出所需要的构造器ConstructorArgumentValues cargs mbd.getConstructorArgumentValues();resolvedValues new ConstructorArgumentValues();//找出构造方法的参数个数并根据cargs构建ConstructorArgumentValues对象minNrOfArgs resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);}//代码块四对candidates进行排序AutowireUtils.sortConstructors(candidates);//计算权重int minTypeDiffWeight Integer.MAX_VALUE;//存放摸棱两可的构造器SetConstructor? ambiguousConstructors null;DequeUnsatisfiedDependencyException causes null;for (Constructor? candidate : candidates) {int parameterCount candidate.getParameterCount();//因为进行了排序如果当前的parameterCountargsToUse.length,那么后续candidate.parameterCount总是小于argsToUse.lengthif (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;}//当前构造方法参数个数不满足要求跳过本次循环if (parameterCount minNrOfArgs) {continue;}// 参数持有者ArgumentsHolder argsHolder;//构造器参数类型数组Class?[] paramTypes candidate.getParameterTypes();if (resolvedValues ! null) {try {//得到当前构造器的方法参数名字数组String[] paramNames ConstructorPropertiesChecker.evaluate(candidate, parameterCount);if (paramNames null) {ParameterNameDiscoverer pnd this.beanFactory.getParameterNameDiscoverer();if (pnd ! null) {paramNames pnd.getParameterNames(candidate);}}//根据构造方法参数名数组和构造器参数值构建argsHolder//这个方法是遍历构造器的参数名字和参数类型找到与之匹配的resolvedValues中的ValueHolder值并封装成ArgumentsHolder对象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.if (parameterCount ! explicitArgs.length) {continue;}argsHolder new ArgumentsHolder(explicitArgs);}//计算差异值当多个构造方法的参数个数相同时通过差异值决定使用哪个构造方法//mbd.isLenientConstructorResolution()是否为宽松模式默认是宽松模式int typeDiffWeight (mbd.isLenientConstructorResolution() ?argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));// Choose this constructor if it represents the closest match.//如果当前构造器的差异值比minTypeDiffWeight小将当前构造器的差异值赋值给minTypeDiffWeight变量if (typeDiffWeight minTypeDiffWeight) {//最终使用的构造器constructorToUse赋值为当前构造器constructorToUse candidate;//最终使用的参数持有者argsHolderToUse赋值为当前的argsHolderargsHolderToUse argsHolder;//最终使用的构造器参数argsToUse赋值为当前的argsHolder的argumentsargsToUse argsHolder.arguments;minTypeDiffWeight typeDiffWeight;ambiguousConstructors null;}else if (constructorToUse ! null typeDiffWeight minTypeDiffWeight) {// 如果两个构造器的差异值相等就会将它放入ambiguousConstructors中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) {//代码块五将推断出来的构造方法信息缓存到BD中argsHolderToUse.storeCache(mbd, constructorToUse);}}Assert.state(argsToUse ! null, Unresolved constructor arguments);//根据推断出来的构造器及其参数创建bean实例并封装到bw对象中bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));return bw;}
这个方法大致总结为 1先后bd缓存中获取构造函数的相关信息构造器、构造参数如果缓存是部分准备好的构造函数参数需要转换成最终可使用的构造参数。 2缓存中获取构造器或构造参数失败有如下两种情况 a.通过determineCandidateConstructors()推断出来的构造器不为null,直接将推断出来的构造器存放到构造器数组candidates。 b.通过determineCandidateConstructors()推断出来的构造器为null,拿到当前beanClass中的所有构造器存放到构造器数组candidates。 3如果candidates中只有一个构造器且为无参构造将该构造器信息缓存到bd中同时通过这个无参构造器创建bean实例对象并封装到BeanWrapperImpl中返回。 4设置构造器最小参数值minNrOfArgs。如果手动设置了构造器参数最小参数值就为设置的参数的个数。通过createBean(beanName, mbd, args)api设置args或者通过xml中constructor-arg标签设置。或者是BeanDefinition.getConstructorArgumentValues().addArgumentValues()/BeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue()方式设置获取bd中的构造参数值并封装成ConstructorArgumentValues对象resolvedValues。 5对candidates中的构造器进行排序。创建构造器差异值变量minTypeDiffWeight并将其赋值为Integer.MAX_VALUE构造器差异值最小的即为最优解;创建 ambiguousConstructors 变量用于存放模棱两可的构造器。 6遍历candidates获取当前构造器的参数个数parameterCount如果上一个回合已经推断出constructorToUse和argsToUse,且argsToUse的长度大于当前构造器的参数个数直接退出遍历。因为进行了排序如果当前的parameterCountargsToUse.length,那么后续candidate.parameterCount可能总是小于argsToUse.length虽然可能存在修饰符不同的情况但是这里排序修饰符比构造参数个数优先级高。在遍历的代码块中有一个重要的逻辑就是计算差异值而计算差异值的前提是两个构造器的构造参数个数相同。如果当前构造器比前一个构造器的构造参数个数少是没有资格进行差异值比较的。 7如果当前构造器的个数parameterCount 小于最小构造器参数个数minNrOfArgs跳过本次循环进行下次循环pubulic修饰的构造器不满足可能protected或private修饰的构造器满足。 8构建参数持有者ArgumentsHolder argsHolder获取当前构造器的构造器参数类型数组Class?[] paramTypes。 iresolvedValues值不为空。获取当前构造器参数名字数组。遍历构造器的参数名字和参数类型数组找到与之匹配的resolvedValues中的ValueHolder值并封装成ArgumentsHolder对象。 ii)explicitArgs不为空直接通过explicitArgs构建ArgumentsHolder对象。 9计算差异值当多个构造方法的参数个数相同时通过差异值决定使用哪个构造方法。 i如果当前构造器的差异值比minTypeDiffWeight小将当前构造器的差异值赋值给minTypeDiffWeight变量并把最终使用的构造器constructorToUse赋值为当前构造器 constructorToUse candidate; 最终使用的参数持有者argsHolderToUse赋值为当前的argsHolder argsHolderToUse argsHolder; 最终使用的构造器参数argsToUse赋值为当前的argsHolder的arguments。同时将ambiguousConstructors值设置为null. ii 如果当前构造器的差异值与minTypeDiffWeig相等就会将它放入ambiguousConstructors如果为null先创建ambiguousConstructors中。 10如果存在模棱两可的构造器且不是宽松模式下抛出异常。严格模式下spring认为不能存在摸棱两可的构造器而且宽松模式和严格模式下差异值计算的算法也不一样。spring默认为宽松模式。 11将推断出来的构造方法信息缓存到BD中,并根据推断出来的构造器及其参数创建bean实例并封装到bw对象中返回。
i代码块四构造器排序规则 构造器的排序规则。public修饰的构造器排在前面如果同为public类型比较构造器的参数个数参数个数多的排在前面。 public static final ComparatorExecutable EXECUTABLE_COMPARATOR (e1, e2) - {int result Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers()));//为什么在自动注入方式为构造方法注入时会选择构造方法参数比较多的那个构造方法return result ! 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount());};
ii代码块五storeCache()将推断出来的构造方法信息缓存到BD中
//将推断出来的构造方法信息缓存到BD中public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {synchronized (mbd.constructorArgumentLock) {mbd.resolvedConstructorOrFactoryMethod constructorOrFactoryMethod;mbd.constructorArgumentsResolved true;if (this.resolveNecessary) {mbd.preparedConstructorArguments this.preparedArguments;}else {mbd.resolvedConstructorArguments this.arguments;}}}}
三、总结 spring推断构造方法分如下几种情况 1不使用自动装配时。 1无构造方法或只有一个无参构造方法的情况下返回null 2有且只有一个有参构造方法时返回这个有参构造方法 3有多个构造方法时返回null
2使用Autowired注入时. 1如果只有一个构造方法添加了Autowired(requiredtrue),返回这个构造方法 2如果有一个构造方法添加了Autowired(requiredtrue)其他构造方法再添加Autowired注解抛出异常 3如果有多个构造方法添加了Autowired(requiredfalse除了返回所以加了Autowired(requiredfalse的构造方法如果提供了无参构造方法也会返回无参构造方法后续继续推断构造方法。
3使用自动注入时。 根据构造方法的参数类型或参数个数找到最优的构造方法默认最优的为参数类型为spring中依赖最多且参数个数最长的那个。