游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

Spring源码createBeanInstance

  前文提到在createBeanInstance中实例化Bean一共有四种方式:Supplier回调:obtainFromSupplier()工厂方法初始化:instantiateUsingFactoryMethod()构造函数自动注入初始化:autowireConstructor()默认构造函数注入:instantiateBean()
  这篇就来分析两种方式。还是在AbstractAutowireCapableBeanFactory。createBeanInstance方法中。上述代码省略booleanresolvedfalse;booleanautowireNecessaryfalse;调用getBean()时不传入参数if(argsnull){synchronized(mbd。constructorArgumentLock)当作用域为原型时、多次调用getBean()时不传入参数,从缓存中获取这段逻辑才会被执行resolvedConstructorOrFactoryMethod缓存了已解析的构造函数或工厂方法if(mbd。resolvedConstructorOrFactoryMethod!null){resolved为true,表示当前bean的构造方法已经确定了,也代表该Bean之前被解析过resolvedtrue;constructorArgumentsResolved:将构造函数参数标记为已解析true就是标记为了已解析默认为false。如果autowireNecessary为true说明是采用有参构造函数注入autowireNecessarymbd。constructorArgumentsResolved;}}}resolvedtrue,表示当前bean的构造方法已经确定了if(resolved){autowireNecessarytrue,表示采用有参构造函数注入if(autowireNecessary){采用有参构造函数注入returnautowireConstructor(beanName,mbd,null,null);}else{构造方法已经确定了,但是没有确定构造方法参数那就表示没有构造方法参数,用无参的构造方法来实例化beanreturninstantiateBean(beanName,mbd);}}
  上面这段代码的逻辑为:如果没有显示的传入参数,判断resolvedConstructorOrFactoryMethod是否不为空,如果不为空,则存在缓存,直接使用已经解析了的构造函数。然后根据autowireNecessary参数来判断是使用有参构造函数自动注入还是使用无参构造函数注入。autowireConstructor
  先来看一下autowireConstructor方法,也就是有参构造函数自动注入。进入ConstructorResolver类的autowireConstructor方法。该方法有四个参数:beanName:当前Bean的名称。mbd:当前Bean的定义。chosenCtors:经过筛选的构造方法列表。可能为null。explicitArgs:开发者在调用getBean方法时显示传递的参数。publicBeanWrapperautowireConstructor(StringbeanName,RootBeanDefinitionmbd,NullableConstructorlt;?〔〕chosenCtors,NullableObject〔〕explicitArgs){BeanWrapperImplbwnewBeanWrapperImpl();this。beanFactory。initBeanWrapper(bw);最终需要使用的构造方法变量Constructorlt;?constructorToUsenull;ArgumentsHolderargsHolderToUsenull;最终需要使用的参数变量Object〔〕argsToUsenull;getBean()方法指定了构造方法参数if(explicitArgs!null){argsToUseexplicitArgs;}else{从缓存中获取构造方法和构造方法参数当作用域为原型时并多次调用getBean()时没有传递参数创建Bean是会走这段缓存逻辑。为单例只会从一次,之后的getBean()都会从单例池获取。Object〔〕argsToResolvenull;synchronized(mbd。constructorArgumentLock){resolvedConstructorOrFactoryMethod:缓存已解析的构造函数或工厂方法constructorToUse(Constructorlt;?)mbd。resolvedConstructorOrFactoryMethod;找到了mbd中缓存的构造方法constructorArgumentsResolved:将构造函数参数标记为已解析true就是标记为了已解析if(constructorToUse!nullmbd。constructorArgumentsResolved){resolvedConstructorArguments:获得已完全解析的构造函数参数(参数类型已经确定,能够直接进行使用)正常情况下resolvedConstructorArguments的值就是nullargsToUsembd。resolvedConstructorArguments;if(argsToUsenull){获得部分准备好的构造函数参数(该参数的类型是不确定的,需要进行解析)argsToResolvembd。preparedConstructorArguments;}}}如果存在构造函数参数,那么则对参数值进行类型转化如给定方法的构造函数Person(int)则通过此方法后就会把配置中的5转换为5constructorargindex0value5缓存中的值可能是原始值也可能是最终值if(argsToResolve!null){argsToUseresolvePreparedArguments(beanName,mbd,bw,constructorToUse,argsToResolve,true);}}如果待使用的构造方法为null,或待使用的构造方法参数为null,也就是没有缓存这个if代码很长,但其实就去找构造方法、构造方法参数并赋值给constructorToUse、argsToUseif(constructorToUsenullargsToUsenull){chosenCtors表示所指定的构造方法没有指定则获取beanClass中的所有的构造方法作为候选者从这些构造方法中选择一个构造方法Constructorlt;?〔〕candidateschosenCtors;if(candidatesnull){Classlt;?beanClassmbd。getBeanClass();try{mbd。isNonPublicAccessAllowed():默认为truegetDeclaredConstructors():获得本类所有构造方法getConstructors:获得本类的所有公有构造方法candidates(mbd。isNonPublicAccessAllowed()?beanClass。getDeclaredConstructors():beanClass。getConstructors());}catch(Throwableex){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,ResolutionofdeclaredconstructorsonbeanClass〔beanClass。getName()〕fromClassLoader〔beanClass。getClassLoader()〕failed,ex);}}如果只有一个构造方法,并且没有显示指定构造方法参数并且在xml中没有使用constructorarg标签则需要判断是不是无参构造方法,如果是则使用无参构造方法进行实例化if(candidates。length1explicitArgsnull!mbd。hasConstructorArgumentValues()){Constructorlt;?uniqueCandidatecandidates〔0〕;判断是不是无参构造方法if(uniqueCandidate。getParameterCount()0){synchronized(mbd。constructorArgumentLock){确定了构造方法之后进行缓存mbd。resolvedConstructorOrFactoryMethoduniqueCandidate;mbd。constructorArgumentsResolvedtrue;mbd。resolvedConstructorArgumentsEMPTYARGS;}进行实例化bw。setBeanInstance(instantiate(beanName,mbd,uniqueCandidate,EMPTYARGS));returnbw;}}如果入参chosenCtors不为null,也就是找到了构造方法,或者autowireMode是构造方法自动注入则可能要自动选择构造方法booleanautowiring(chosenCtors!nullmbd。getResolvedAutowireMode()AutowireCapableBeanFactory。AUTOWIRECONSTRUCTOR);记录解析后的构造方法参数值ConstructorArgumentValuesresolvedValuesnull;minNrOfArgs:表示所有构造方法中,参数个数最少的构造方法的参数个数是多少intminNrOfArgs;if(explicitArgs!null){minNrOfArgsexplicitArgs。length;}else{从BeanDefinition中获取所设置的构造方法参数值值来源于constructorarg标签中的index属性的值这个值可以随便写ConstructorArgumentValuescargsmbd。getConstructorArgumentValues();记录解析后的构造方法参数值resolvedValuesnewConstructorArgumentValues();解析参数个数值来源于constructorarg标签中的index属性的值这个值可以随便写minNrOfArgsresolveConstructorArguments(beanName,mbd,bw,cargs,resolvedValues);}按构造方法的参数个数降序排序,先排序public构造函数,参数降序排列然后排序非public的构造函数,参数降序排列AutowireUtils。sortConstructors(candidates);intminTypeDiffWeightInteger。MAXVALUE;SetConstructorlt;?ambiguousConstructorsnull;LinkedListUnsatisfiedDependencyExceptioncausesnull;遍历构造方法,找到一个最合适的先看参数列表最长的构造方法,根据每个参数的参数类型和参数名去找beanfor(Constructorlt;?candidate:candidates){当前构造方法的参数个数intparameterCountcandidate。getParameterCount();已经找到选用的构造函数且该参数个数大于当前遍历的,则不用继续遍历了上面已经按照参数个数降序排列了if(constructorToUse!nullargsToUse!nullargsToUse。lengthparameterCount){break;}在遍历某个构造方法时,如果当前遍历的参数个数小于所指定的参数个数则忽略该构造方法minNrOfArgs已经是最小的了,比他还小肯定是不符合我所需要的,就不必往下执行了if(parameterCountminNrOfArgs){continue;}ArgumentsHolderargsHolder;当前遍历到的构造方法的参数类型Classlt;?〔〕paramTypescandidate。getParameterTypes();当getBean()方法没有显示指定构造方法参数,resolvedValues不为nullif(resolvedValues!null){try{获取参数名查看是否在构造方法上使用ConstructorProperties注解来定义构造方法参数的名字String〔〕paramNamesConstructorPropertiesChecker。evaluate(candidate,parameterCount);if(paramNamesnull){ParameterNameDiscoverer用于解析方法、构造函数上的参数名称ParameterNameDiscovererpndthis。beanFactory。getParameterNameDiscoverer();if(pnd!null){获取构造函数的参数名称paramNamespnd。getParameterNames(candidate);}}根据当前构造方法的参数类型和参数名从beanFactory中得到bean作为参数值resolvedValues:解析后的构造方法参数值paramTypes:当前构造方法中每个参数的属性类型paramNames:当前构造方法中每个参数的属性名称getUserDeclaredConstructor(candidate):获取父类中被重写的构造方法argsHoldercreateArgumentArray(beanName,mbd,resolvedValues,bw,paramTypes,paramNames,getUserDeclaredConstructor(candidate),autowiring,candidates。length1);}catch(UnsatisfiedDependencyExceptionex){如果找不到相匹配的,也不会直接报错只能说明当前遍历的构造方法不能用if(logger。isTraceEnabled()){logger。trace(Ignoringconstructor〔candidate〕ofbeanbeanName:ex);}Swallowandtrynextconstructor。if(causesnull){causesnewLinkedList();}causes。add(ex);continue;}}else{getBean()方法指定了构造方法参数值当前构造方法参数个数与传入的参数个数不相等,跳出本次循环if(parameterCount!explicitArgs。length){continue;}如果参数个数匹配,则把所有参数值封装为一个ArgumentsHolder对象argsHoldernewArgumentsHolder(explicitArgs);}执行到这里,表示当前构造方法可用,并且也找到了对应的构造方法参数值但是还需要判断,当前构造方法是不是最合适的,也许还有另外的构造方法更合适根据参数类型和参数值计算权重Lenient宽松,默认宽松模式是开启的严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常宽松模式:使用具有最接近的模式进行匹配inttypeDiffWeight(mbd。isLenientConstructorResolution()?argsHolder。getTypeDifferenceWeight(paramTypes):argsHolder。getAssignabilityWeight(paramTypes));Choosethisconstructorifitrepresentstheclosestmatch。如果当前构造方法的权重比较小,则表示当前构造方法更合适将当前构造方法和所找到参数值作为待使用的遍历下一个构造方法if(typeDiffWeightminTypeDiffWeight){constructorToUsecandidate;argsHolderToUseargsHolder;argsToUseargsHolder。arguments;minTypeDiffWeighttypeDiffWeight;ambiguousConstructorsnull;}elseif(constructorToUse!nulltypeDiffWeightminTypeDiffWeight){如果权重一样,则记录在ambiguousConstructors中,继续遍历下一个构造方法if(ambiguousConstructorsnull){ambiguousConstructorsnewLinkedHashSet();ambiguousConstructors。add(constructorToUse);}ambiguousConstructors。add(candidate);}循环结束}遍历完所有构造方法后,没有找到合适的构造方法,则报错if(constructorToUsenull){if(causes!null){UnsatisfiedDependencyExceptionexcauses。removeLast();for(Exceptioncause:causes){this。beanFactory。onSuppressedException(cause);}throwex;}thrownewBeanCreationException(mbd。getResourceDescription(),beanName,Couldnotresolvematchingconstructor(hint:specifyindextypenameargumentsforsimpleparameterstoavoidtypeambiguities));}如果存在权重一样的构造方法并且不是宽松模式,也报错因为权重一样,Spring不知道该用哪个如果是宽松模式则不会报错,Spring会用找到的第一个elseif(ambiguousConstructors!null!mbd。isLenientConstructorResolution()){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,AmbiguousconstructormatchesfoundinbeanbeanName(hint:specifyindextypenameargumentsforsimpleparameterstoavoidtypeambiguities):ambiguousConstructors);}如果不是通过getBean()方法指定的参数,那么就把找到的构造方法参数进行缓存if(explicitArgsnullargsHolderToUse!null){缓存找到的构造方法argsHolderToUse。storeCache(mbd,constructorToUse);}}得到了构造方法和构造方法的参数值之后,就可以进行实例化了Assert。state(argsToUse!null,Unresolvedconstructorarguments);bw。setBeanInstance(instantiate(beanName,mbd,constructorToUse,argsToUse));returnbw;}
  代码很长,但总体来说就是确定一件事情。确定构造函数、构造函数参数,然后调用instantiate方法进行bean的实例化。
  总体思路:先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化。如果没有确定的构造方法或构造方法参数值,又分为以下流程:a。如果没有确定构造方法,那么则找出类中所有的构造方法。b。如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化。c。如果有多个构造方法或者当前Bean的注入方式是构造方法自动注入,则要自动选择构造方法。d。根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数。如果没有指定,从BeanDefinition的constructorArgumentValues属性获取。e。对所有的构造方法进行排序,public构造函数优先参数数量降序,非public构造函数参数数量降序。f。遍历每个构造方法。g。如果调用getBean方法时,没有显示指定构造方法参数值,那么则根据当前循环到的构造方法得到构造参数类型、构造参数名称与解析后的构造方法参数值(resolvedValues)进行匹配,构建ArgumentsHolder对象。h。如果调用getBean方法时,指定构造方法参数值,就直接利用传入的构造方法参数值构建ArgumentsHolder对象。i。如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的(分越少优先级越高)。为什么分越少优先级越高?
  主要是计算找到的bean和构造方法参数类型匹配程度有多高
  假设bean的类型为A,A的父类是B,B的父类是C,同时A实现了接口D如果构造方法的参数类型为A,那么完全匹配,得分为0如果构造方法的参数类型为B,那么得分为2如果构造方法的参数类型为C,那么得分为4如果构造方法的参数类型为D,那么得分为1
  可以直接使用如下代码进行测试:Object〔〕objectsnewObject〔〕{newA()};0System。out。println(MethodInvoker。getTypeDifferenceWeight(newClass〔〕{A。class},objects));2System。out。println(MethodInvoker。getTypeDifferenceWeight(newClass〔〕{B。class},objects));4System。out。println(MethodInvoker。getTypeDifferenceWeight(newClass〔〕{C。class},objects));1System。out。println(MethodInvoker。getTypeDifferenceWeight(newClass〔〕{D。class},objects));举例
  各位小伙伴可以下去跑一下例子,打打断点。举例一、1、创建A、B类,其中A类有B属性、name属性。并且在A(Bb)这个构造方法加上Autowired注解,表示要使用这个构造方法实例化对象。publicclassA{privateBb;privateStringname;publicA(){}AutowiredpublicA(Bb){this。bb;}publicA(Stringname){this。namename;}publicA(Bb,Stringname){this。bb;this。namename;}publicBgetB(){returnb;}publicvoidsetB(Bb){this。bb;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this。namename;}OverridepublicStringtoString(){returnA{bb,namename};}}publicclassB{}2、springconfig4。xmllt;?xmlversion1。0encodingUTF8?beansxmlnshttp:www。springframework。orgschemabeansxmlns:xsihttp:www。w3。org2001XMLSchemainstancexmlns:contexthttp:www。springframework。orgschemacontextxsi:schemaLocationhttp:www。springframework。orgschemabeanshttp:www。springframework。orgschemabeansspringbeans。xsdhttp:www。springframework。orgschemacontexthttps:www。springframework。orgschemacontextspringcontext。xsdbeanclasscom。gongj。create。Aidaabeanbeanclasscom。gongj。create。Bidbbbeancontext:componentscanbasepackagecom。gongj。createcontext:componentscanbeans3、启动publicstaticvoidmain(String〔〕args){ClassPathXmlApplicationContextcontextnewClassPathXmlApplicationContext(springconfig4。xml);Aa(A)context。getBean(aa);System。out。println(a);}结果:A{bcom。gongj。create。B27808f31,namenull}举例二、1、修改springconfig4。xml配置内容lt;?xmlversion1。0encodingUTF8?beansxmlnshttp:www。springframework。orgschemabeansxmlns:xsihttp:www。w3。org2001XMLSchemainstancexmlns:contexthttp:www。springframework。orgschemacontextxsi:schemaLocationhttp:www。springframework。orgschemabeanshttp:www。springframework。orgschemabeansspringbeans。xsdhttp:www。springframework。orgschemacontexthttps:www。springframework。orgschemacontextspringcontext。xsd!这里使用constructorargbeanclasscom。gongj。create。Aidaaconstructorargindex1valuegongjconstructorargconstructorargindex0refbbconstructorargbeanbeanclasscom。gongj。create。Bidbbbeancontext:componentscanbasepackagecom。gongj。createcontext:componentscanbeans2、启动publicstaticvoidmain(String〔〕args){ClassPathXmlApplicationContextcontextnewClassPathXmlApplicationContext(springconfig4。xml);Aa(A)context。getBean(aa);System。out。println(a);}
  各位可以猜猜运行结果是什么?结果是报错!
  那小杰将Autowired注解标注在A(Bb,Stringname)构造方法上,结果又是如何?AutowiredpublicA(Bb,Stringname){this。bb;this。namename;}结果:A{bcom。gongj。create。B3e57cd70,namegongj}举例三、1、将A的作用域修改为prototype。beanclasscom。gongj。create。Aidaascopeprototypeconstructorargindex0refbbconstructorargconstructorargindex1valuegongjconstructorargbean2、启动publicstaticvoidmain(String〔〕args){ClassPathXmlApplicationContextcontextnewClassPathXmlApplicationContext(springconfig4。xml);Aa(A)context。getBean(aa);System。out。println(aa。hashCode());Aa2(A)context。getBean(aa,newB(),uanjfjef);System。out。println(a2a2。hashCode());Aa3(A)context。getBean(aa);System。out。println(a3a3。hashCode());}结果:A{bcom。gongj。create。B3e57cd70,namegongj}161960012用了传入的值A{bcom。gongj。create。B2c039ac6,nameuanjfjef}1484594489用了缓存的值,而且并没有缓存传入的值A{bcom。gongj。create。B3e57cd70,namegongj}1489069835
  其中有几个方法简单的提一下:resolveConstructorArguments
  解析构造方法的参数值。可能会创建Bean。比如上述举例二。privateintresolveConstructorArguments(StringbeanName,RootBeanDefinitionmbd,BeanWrapperbw,ConstructorArgumentValuescargs,ConstructorArgumentValuesresolvedValues){获得当前beanFatory类型转换器TypeConvertercustomConverterthis。beanFactory。getCustomTypeConverter();获得当前beanFatory类型转换器为null,则使用bw,bw实现了TypeConverterTypeConverterconverter(customConverter!null?customConverter:bw);为给定的BeanFactory和BeanDefinition创建一个BeanDefinitionValueResolverBeanDefinitionValueResolvervalueResolvernewBeanDefinitionValueResolver(this。beanFactory,beanName,mbd,converter);获得constructorarg标签的个数intminNrOfArgscargs。getArgumentCount();先遍历cargs中的indexedArgumentValuesindexedArgumentValues存的是某个index对应的构造方法参数值for(Map。EntryInteger,ConstructorArgumentValues。ValueHolderentry:cargs。getIndexedArgumentValues()。entrySet()){intindexentry。getKey();if(index0){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,Invalidconstructorargumentindex:index);}if(indexminNrOfArgs){minNrOfArgsindex1;}获得构造方法参数值ConstructorArgumentValues。ValueHoldervalueHolderentry。getValue();if(valueHolder。isConverted()){把该数据添加到resolvedValues对象中resolvedValues。addIndexedArgumentValue(index,valueHolder);}else{把值转化为对应的类型获得constructorarg的valueresolveValueIfNecessary:这里可能会创建bean因为constructorarg里面有个ref属性可以引用其他bean。ObjectresolvedValuevalueResolver。resolveValueIfNecessary(constructorargument,valueHolder。getValue());ConstructorArgumentValues。ValueHolderresolvedValueHoldernewConstructorArgumentValues。ValueHolder(resolvedValue,valueHolder。getType(),valueHolder。getName());resolvedValueHolder。setSource(valueHolder);把该数据添加到resolvedValues对象中resolvedValues。addIndexedArgumentValue(index,resolvedValueHolder);}}for循环结束把genericArgumentValues中的值进行类型转化然后添加到resolvedValues中去根据上述循环逻辑差不多for(ConstructorArgumentValues。ValueHoldervalueHolder:cargs。getGenericArgumentValues()){if(valueHolder。isConverted()){resolvedValues。addGenericArgumentValue(valueHolder);}else{ObjectresolvedValuevalueResolver。resolveValueIfNecessary(constructorargument,valueHolder。getValue());ConstructorArgumentValues。ValueHolderresolvedValueHoldernewConstructorArgumentValues。ValueHolder(resolvedValue,valueHolder。getType(),valueHolder。getName());resolvedValueHolder。setSource(valueHolder);resolvedValues。addGenericArgumentValue(resolvedValueHolder);}}for循环结束returnminNrOfArgs;}
  首先获得当前Bean的constructorarg标签的个数minNrOfArgs,然后遍历cargs中的indexedArgumentValues元素,获取每个对象的key(也就是constructorarg标签的index元素),与minNrOfArgs进行比较。顺便将key和value添加到resolvedValues对象中。createArgumentArray
  构造参数持有者。拥有最终要使用的构造参数。privateArgumentsHoldercreateArgumentArray(StringbeanName,RootBeanDefinitionmbd,NullableConstructorArgumentValuesresolvedValues,BeanWrapperbw,Classlt;?〔〕paramTypes,NullableString〔〕paramNames,Executableexecutable,booleanautowiring,booleanfallback)throwsUnsatisfiedDependencyException{TypeConvertercustomConverterthis。beanFactory。getCustomTypeConverter();TypeConverterconverter(customConverter!null?customConverter:bw);根据参数类型的个数初始化出来对应的ArgumentsHolderArgumentsHolderargsnewArgumentsHolder(paramTypes。length);SetConstructorArgumentValues。ValueHolderusedValueHoldersnewHashSet(paramTypes。length);SetStringautowiredBeanNamesnewLinkedHashSet(4);循环执行for(intparamIndex0;paramIndexparamTypes。length;paramIndex){获得参数类型Classlt;?paramTypeparamTypes〔paramIndex〕;获得参数名称StringparamName(paramNames!null?paramNames〔paramIndex〕:);Trytofindmatchingconstructorargumentvalue,eitherindexedorgeneric。尝试查找匹配的构造函数参数值,无论是索引的还是通用的ConstructorArgumentValues。ValueHoldervalueHoldernull;如果指定了构造方法参数值,那么则看当前paramType有没有对应的值if(resolvedValues!null){拿到第paramIndex位置的构造方法参数值,会根据传进去的类型、名称进行匹配如果类型、名称不相等则返回nullvalueHolderresolvedValues。getArgumentValue(paramIndex,paramType,paramName,usedValueHolders);如果找不到直接匹配项,尝试一个通用的,无类型的参数值作为后备,类型转换后可以匹配(例如,Stringint)。if(valueHoldernull(!autowiringparamTypes。lengthresolvedValues。getArgumentCount())){valueHolderresolvedValues。getGenericArgumentValue(null,null,usedValueHolders);}}如果找到了对应的值,则进行类型转化,把转化前的值存在args。rawArguments中转化后的值存在args。arguments中if(valueHolder!null){usedValueHolders。add(valueHolder);ObjectoriginalValuevalueHolder。getValue();ObjectconvertedValue;if(valueHolder。isConverted()){convertedValuevalueHolder。getConvertedValue();args。preparedArguments〔paramIndex〕convertedValue;}else{为给定的方法或构造函数创建一个新的MethodParameter。MethodParametermethodParamMethodParameter。forExecutable(executable,paramIndex);try{进行类型转换convertedValueconverter。convertIfNecessary(originalValue,paramType,methodParam);}catch(TypeMismatchExceptionex){thrownewUnsatisfiedDependencyException(mbd。getResourceDescription(),beanName,newInjectionPoint(methodParam),Couldnotconvertargumentvalueoftype〔ObjectUtils。nullSafeClassName(valueHolder。getValue())〕torequiredtype〔paramType。getName()〕:ex。getMessage());}ObjectsourceHoldervalueHolder。getSource();if(sourceHolderinstanceofConstructorArgumentValues。ValueHolder){ObjectsourceValue((ConstructorArgumentValues。ValueHolder)sourceHolder)。getValue();将resolveNecessary变量赋值为true,该变量会影响resolvedConstructorArguments:缓存完全解析的构造函数参数preparedConstructorArguments:缓存部分准备好的构造函数参数这两个参数是谁为null值args。resolveNecessarytrue;args。preparedArguments〔paramIndex〕sourceValue;}}args。arguments〔paramIndex〕convertedValue;args。rawArguments〔paramIndex〕originalValue;}else{如果上述逻辑,没有找到对应的值。举例中的举例一就会走该代码分支为给定的方法或构造函数创建一个新的MethodParameter。MethodParametermethodParamMethodParameter。forExecutable(executable,paramIndex);if(!autowiring){thrownewUnsatisfiedDependencyException(mbd。getResourceDescription(),beanName,newInjectionPoint(methodParam),Ambiguousargumentvaluesforparameteroftype〔paramType。getName()〕didyouspecifythecorrectbeanreferencesasarguments?);}如果autowiring的值为true,也就是如果入参chosenCtors不为null,也就是找到了构造方法或者autowireMode是构造方法自动注入,则可能要自动选择构造方法booleanautowiring(chosenCtors!nullmbd。getResolvedAutowireMode()AutowireCapableBeanFactory。AUTOWIRECONSTRUCTOR);try{该方法内部会调用resolveDependency方法,得到一个bean,resolveDependency方法很重要。ObjectautowiredArgumentresolveAutowiredArgument(methodParam,beanName,autowiredBeanNames,converter,fallback);args。rawArguments〔paramIndex〕autowiredArgument;args。arguments〔paramIndex〕autowiredArgument;args。preparedArguments〔paramIndex〕autowiredArgumentMarker;将resolveNecessary变量赋值为true,该变量会影响resolvedConstructorArguments:缓存完全解析的构造函数参数preparedConstructorArguments:缓存部分准备好的构造函数参数这两个参数是否为nullargs。resolveNecessarytrue;}catch(BeansExceptionex){thrownewUnsatisfiedDependencyException(mbd。getResourceDescription(),beanName,newInjectionPoint(methodParam),ex);}}}for(StringautowiredBeanName:autowiredBeanNames){this。beanFactory。registerDependentBean(autowiredBeanName,beanName);if(logger。isDebugEnabled()){logger。debug(AutowiringbytypefrombeannamebeanNamevia(executableinstanceofConstructor?constructor:factorymethod)tobeannamedautowiredBeanName);}}最后,返回找到的值returnargs;}
  根据当前构造方法的参数类型、参数名称与上面解析得到的构造方法参数值进行匹配,如果匹配成功返回构造方法的参数值,进行类型转换。然后将必要的属性进行赋值,最后进行返回。instantiate
  instantiate方法,该方法在SimpleInstantiationStrategy类中实现。OverridepublicObjectinstantiate(RootBeanDefinitionbd,NullableStringbeanName,BeanFactoryowner,finalConstructorlt;?ctor,Object。。。args){bd。hasMethodOverrides():是否为此bean定义了方法重写,方法返回true说明重写了if(!bd。hasMethodOverrides()){没有重写,直接使用反射实例化即可if(System。getSecurityManager()!null){useownprivilegedtochangeaccessibility(whensecurityison)AccessController。doPrivileged((PrivilegedActionObject)(){ReflectionUtils。makeAccessible(ctor);returnnull;});}通过BeanUtils直接使用构造器对象实例化beanreturnBeanUtils。instantiateClass(ctor,args);}else{重写了生成CGLIB创建的子类对象returninstantiateWithMethodInjection(bd,beanName,owner,ctor,args);}}
  如果该Bean没有配置lookupmethod、replacedmethod标签或者Lookup注解,则直接通过反射的方式实例化Bean。如果配置了则需要使用CGLIB进行动态代理。instantiateBean
  使用无参的构造方法来实例化bean。protectedBeanWrapperinstantiateBean(finalStringbeanName,finalRootBeanDefinitionmbd){try{ObjectbeanInstance;finalBeanFactoryparentthis;if(System。getSecurityManager()!null){beanInstanceAccessController。doPrivileged((PrivilegedActionObject)()getInstantiationStrategy()。instantiate(mbd,beanName,parent),getAccessControlContext());}else{beanInstancegetInstantiationStrategy()。instantiate(mbd,beanName,parent);}BeanWrapperbwnewBeanWrapperImpl(beanInstance);initBeanWrapper(bw);returnbw;}catch(Throwableex){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,Instantiationofbeanfailed,ex);}}
  instantiateBean方法相比于instantiateUsingFactoryMethod、autowireConstructor方法实在是太简单了,因为它没有参数,所以不需要确定构造方法、构造方法参数,直接调用实例化策略进行实例化就可以了。
  作者:程序员小杰
  链接:https:juejin。cnpost7005388320016433165

不满足于汽车业务,小鹏汽车开始准备上天了?未来的交通是什么样子的?众所周知,1886年1月29日被认为是世界汽车的诞生日,因为卡尔本茨在这一天获得了世界上第一台内燃机汽车的专利。然而,大多数人都忽视的是,在卡尔本……荣耀智慧屏X2体验这就是客厅C位的最佳选择自从荣耀推出智慧屏产品,家庭的智慧生活格局就迎来了全面的升级。智慧屏不仅仅是影音享受的工具,更是成为了家庭的智慧中枢。最近荣耀又带来了全新产品荣耀智慧屏X2,在优秀屏幕素……为什么签了三方协议电子税务局显示没签呢?我来回答!我发现自己真是个多面手,不带这样夸自己的啊!朋友笑话我说。最近朋友问我,她在电子税务局缴税时,发现没有三方协议,正好这个事情我也碰到了,于是发到这里,凡是碰到这种情况的看……每次10分钟跟我学Python(第三十五次课)大家好!我是幻化意识流。今天继续跟我学Python。大家经常会去超市购物,我们一般都会先找一个购物车(shoppingcar),最初这个购物车是空的,因为我们可能并不知道……初入职场亦能如鱼得水!科大讯飞智能办公本T2用过都竖大拇指前言寒窗苦读十几年,我们都希望拿着沉甸甸的学历文凭找到一份称心如意的好工作。反正我是这样,相信大家亦如此。不过每一位职场新人,入职前都是信心满满,干劲十足;然而入职三年,……Synchronoss宣布首席财务官过渡计划公司重申2021财年指南云技术、短信收发以及数字产品和平台领域的全球领导者和创新者SynchronossTechnologies,Inc。(纳斯达克股票代码:SNCR)今……重庆主城江中游泳的一些思考重庆主城江中游泳杂谈作者:z益yi重庆有两条江,嘉陵江和长江,2019年重庆开始启动了两江四岸的打造。然而关于重庆的两江建设还有一些被忽略的问题值得我们去关注。……明朝的张居正和清朝的李鸿章谁是好人?李鸿章的名字应该是妇孺皆知,因为初中和高中课本都有他的介绍。张居正的名字知道的会少一点,很多人看了电视剧才了解到有这么一个人。张居正是明朝中后期的大学士,内阁首辅。在他人……618手机最终战报群众的眼睛是雪亮的618悄悄的结束啦,相信不少小伙伴和我一样,都有着喜悦的收获。其实每年618最热闹然是手机圈,毕竟手机已经成为人们忠实的伴侣,说一句调侃的话:可以没有男朋友,但是万万不能没有手……姿势对一天2毛!小米11这样购买更好,给自己留条后路小米11的发布让很多人,甚至不是米粉的用户都有些兴奋,甚至有人要把手里的友商手机给换掉,其实大家看重的估计还是性价比,通俗的来说,就是手机足够好,价格足够低。小米11的这个价格……今年315,哪个行业最可能被曝光?一个让所有公关人激动或者说惊恐的年度大戏不知道今年还开不开演了。这戏不是脑残到无语的号称首部公关大戏的《完美关系》,是315晚会,这电视剧里设计了那么多桥段,居然没来一段……告别指纹识别困扰,云米3D人脸识别AI全自动智能门锁eyel一、前言:前后体验过6把以上的指纹锁,不论什么品牌,不论是光学还是电容指纹识别。。。总会遇到老人和孩子难以识别指纹,只能趴上去摁密码的问题。。。之前比较方便的做法是……
紧凑型键鼠如何让办公桌面清新整洁,雷柏9000M多模无线键鼠相信有不少人都有被HR批评办公桌面太乱的经历,在本就繁杂的工作面前,又要让所有东西井井有条,确实令人头疼。在整理桌面这件事上,一定要发挥断舍离精神,想要桌面整洁,必须先要腾出空……ARMIOT从爆品到爆发,AI企业该何去何从?AI产业革新浪潮,一石激起千层浪,芯片市场备受关注。ARM、英特尔、高通等巨头的举措成为了焦点。9月14日,2018Arm人工智能开发者全球峰会于上海举行,汇聚ArmAI……华为Mate40Pro已卖出451万台,未来可期基本上,根据前几天小米的官方发表,小米发表的高级机型11系列在21天内突破了100万台。现在已经超过150万台了。华为最新旗舰mate40系列发布以来已经过了三个月,但在芯片的……域乎数写长三角一体化的加速度,做数字时代的奠基人2020年12月10日,在上海市经济和信息化委员会的指导下,上海智慧城市发展研究院经过为期一个月的线上征集、筛选、梳理,确定了56个由运营商、行业龙头企业、创新型企业等建设的智……一盒泡面450元,盘点世界上最贵的三种泡面一盒泡面450元,啾咪啾咪!谁是泡面界的爱马仕第三名:台湾满汉御品烧牛肉面,售价248元台币,折合54元人民币这玩意主要昂贵在它里面的浓汤,据说用每头牛只有1的特选……夏天开空调使用外循环进风一定比内循环进风降温效果差吗?我们在夏天开空调时,有的时候会选择外循环进风,有的时候会选择内循环进风模式,看到很多文章和视频说使用内循环进风模式降温效果好,也有一些文章和视频说使用外循环进风降温效果比使用内……90的人都不知道微信的这个隐藏极深的功能到底是什么功能这么神秘?天天用着微信通信,到你不知道这个功能的存在。是不是有点不可思议!这个功能等于是一个监视的工具也不为过!你是不是经常在微信朋友圈看到类似这样的广告。如下图……Linux视频教程之使用Zim在Linux桌面上创建一个维基不可否认维基wiki的用处,即使对于一个极客来说也是如此。你可以用它做很多事写笔记和手稿,协作项目,建立完整的网站。还有更多的事,虽然传统的维基体积小,易于安装和维护,甚至更容……为什么很多人不相信我们国家在某些技术上领先了?比如5g?5G技术领先,但核心元件、系统在别人手里,这种领先是空中楼阁。中国其它的领先技术,比华为还难堪,没有核心的东西,只是对资源的整合和利用。象C919,一断供,就得下马。……骑电动三轮车撞死人,还逆行,可能要承担刑事责任前不久,在山东省淄博市周村区一辆电动三轮车与另一辆电动二轮车出现交通事故,三轮车车主孙某无驾驶证,还逆向行驶,与吕某驾驶一辆二轮电动车发生相撞,造成吕某死亡,经交警部门认定,孙……携号转网来了!这些用户却没资格,小心运营商再给你下套大家都知道,现在的手机号已经不单纯只是一串数字了,它绑定了我们各种人脉关系以及一堆互联网安全账号,总之牵一发而动全身,想更改手机卡、更换运营商并非易事。许多手机用户认为,……华为的接班人来了?OPPO或将自研芯片,代号马里亚纳今年的国内手机市场,正在发生着翻天覆地的变化。由于华为受到的芯片制裁,其市场份额正在大幅度缩水,曾经的国产手机一哥现如今在高端旗舰市场当中已经站不稳脚跟,vivo、小米、OPP……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网