专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

0源码基础学习Spring源码系列(一)Bean注入流程

  作者:京东科技韩国凯
  通过本文,读者可以0源码基础的初步学习spring源码,并能够举一反三从此进入源码世界的大米!本文第一部分将介绍Autowired与Resource的区别,第二部分则重点介绍SpringIOC的Bean注入流程。
  由于是第一次阅读源码,文章之中难免存在一些问题,还望包涵指正!一、Autowired与Resource的区别
  用一句话总结两者的区别就是:Autowired会先通过类型注入,即byType,当存在有多个类型时会通过名称注入。Resource则相反,会先通过名称注入,即byName,当名称不存在或有多个名称时会通过类型注入。
  那么通过名称注入与通过类型注入有什么区别呢?创建接口interfaceStuService{StringgetName();}ServiceStu2实现接口并注册beanclassStu2implementsStuService{OverridepublicStringgetName(){returnstu2;}}ServiceStu3实现接口并注册beanclassStu3implementsStuService{OverridepublicStringgetName(){returnstu3;}}1。1Autowired
  那么此时如果我们对StuService注入,Autowired可以选择注入的类型就有两个,分别是Stu2与Stu3。
  需要注意的是,类型有很多种选择:当注册bean与获取bean为同一个类时,类型只有这个类本身。
  例如,我们有获取session的工具类,需要将其注入到spring之中,ComponentclassSessionUtil{publicStringgetSession(){returnsession;}}
  只有一个类,直接注册bean,使用时可以任意选择AutowiredSessionUtilsessionUtil;
  此时Autowired只有一个注册类型,直接注入。当注册bean有多个时,类型为所有注册的bean,实现方式有:实现接口、继承、通过其他方式,例如xml配置注册bean。
  例如上述StuService有多个实现类,每个实现类都注册了bean,因此Autowired可以选择的类型就有两个。AutowiredStuServicestu;
  根据上述的Autowired逻辑,此时有多个类型,那么会根据beanname查找,(即类名首字母小写的),发现stu没有对应的实现类,
  此时会报错:
  Fieldstuincom。example。demo。spring。Stu1requiredasinglebean,but2werefound:
  只需要将stu替换成stu2或stu3即可完成注入。
  继承和其他方式同时有多个bean注入时同理。
  因此,Autowired中类型的定义可以归结为:当注册bean有多个时,类型为所有注册的bean,实现方式有:实现接口、继承、通过其他方式,例如xml配置注册bean或者Bean注册。1。2Resource当只有一个bean时,可以直接注册AutowiredSessionUtilsessionUtil;当有多个bean注册时,如果未指定名称,则beanname为类名首字母小写,指定了bean名称则注册名称为该名称。
  例如上文中Stu1Stu2都未指定bean名称,因此两者的bean名称分别为stu1stu2。
  当使用Bean在方法上注册bean,此时名称为方法名称。Bean()publicStudentgetStudent(){StudentstudentnewStudent();student。setName(bob);student。setId(26);returnstudent;}
  此时该bean名称为getStudent。
  同样,我们也可以注册bean时自定义bean名称Bean(stu1)publicStudentgetStudent(){StudentstudentnewStudent();student。setName(bob);student。setId(26);returnstudent;}Service(stu2)classStu2implementsStuService{OverridepublicStringgetName(){returnstu2;}}Component(stu3)classStu3implementsStuService{OverridepublicStringgetName(){returnstu3;}}
  在引用时指定bean:Resource(namestu2)privateStuServicestu1;1。3Autowired
  当我们使用Resource时,会根据名称也就是stu2去查询,此时bean名称只有一个,查到返回ResourceprivateStu3stu2;
  但是在执行时却发现报错:Beannamedstu2isexpectedtobeoftypecom。example。demo。spring。Stu3butwasactuallyoftypecom。example。demo。spring。Stu2
  这是因为只根据了bean名称去查询,却没有根据bean类型,查到的是Stu2类型的bean,但是期望的却是Stu3,因此会发生类型不匹配。二、SpringIOC的Bean注入流程
  spring的注册流程主要包含两个部分:容器的启动阶段及预热工作Bean的注入流程
  先了解一下几个概念:2。1概念介绍2。1。1配置元数据
  存在于磁盘上的项目中用于描述一个bean的数据,可以是xml、properties、yaml等静态文件,也可以是各种注解描述的对应信息,例如Service、Component描述的一个bean的信息。beanidroleclasscom。wbg。springxmlbean。entity。Rolepropertynameidvalue1propertynameroleNamevalue高级工程师propertynamenotevalue重要人员bean
  以上就是一个由xml定义的配置元数据。2。1。2BeanDefinition与BeanDefinitionReader
  在spring中,无论是那种配置元数据,最终都会转换为BeanDefinition,由BeanDefinition描述要生成并被引用的对象,可以理解为BeanDefinition就是bean的生成模板,或者是bean的说明书,按照BeanDefinition生成bean。
  而将配置元数据转换为BeanDefinition的工作就是由BeanDefinitionReader完成的,对于不同的的配置元数据有不同的Reader完成对应的工作,例如有XmlBeanDefinitionReader读取xml配置信息,PropertiesBeanDefinitionReader读取properties配置信息,AnnotatedBeanDefinitionReader读取注解的配置信息。
  BeanDefinitionReader的作用就是将磁盘上的文件信息或注解信息转化为内存中用于描述bean的BeanDefinition。2。1。3BeanFactoryPostProcessor
  BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点,主要负责对注册到BeanDefinitionRegistry中的一个个的BeanDefinition进行一定程度上的修改与替换。例如我们的配置元信息中有些可能会修改的配置信息散落到各处,不够灵活,修改相应配置的时候比较麻烦,这时我们可以使用占位符的方式来配置。例如配置Jdbc的DataSource连接的时候可以这样配置:beaniddataSourceclassorg。apache。commons。dbcp。BasicDataSourcedestroymethodclosepropertynamemaxIdlevalue{jdbc。maxIdle}propertypropertynamemaxActivevalue{jdbc。maxActive}propertypropertynamemaxWaitvalue{jdbc。maxWait}propertypropertynameminIdlevalue{jdbc。minIdle}propertypropertynamedriverClassNamevalue{jdbc。driverClassName}propertypropertynameurlvalue{jdbc。url}propertypropertynameusernamevalue{jdbc。username}propertypropertynamepasswordvalue{jdbc。password}propertybean
  BeanFactoryPostProcessor就会对注册到BeanDefinitionRegistry中的BeanDefinition做最后的修改,替换占位符为配置文件中的真实的数据。2。1。4BeanDefinitionRegistry
  一个存储BeanDefinition的地方,存储方式为KV值,key为beanName,value为BeanDefinition。2。1。5容器启动阶段
  容器的启动阶段相对比较简单,首先会将存在于各处的磁盘上的配置元信息由各自的Reader读取到内存之中,转换成BeanDefinition,然后注册到BeanDefinationRegistry之中,最后由BeanFactoryPostProcessor进行修改与替换。
  2。1。6BeanFactory与FactoryBean
  BeanFactory与FactoryBean的名字很像,但是确实两个不同的东西。
  根据命名规则来看,BeanFactory是一个Factory,也就是一个存放bean的工厂,在创建bean完成后放到其中,使用是从其中获取。
  而FactoryBean则是一个bean,只不过与不同的的bean不同的是他不仅可以创建本身类型的bean,也可以类似于Factory一样创建一层有包装的新的bean。这个Bean可以返回一个新的类型的bean,在返回之前也可以对其进行加工。ComponentclassFactoryBeanDemoimplementsFactoryBeanStudent{OverridepublicStudentgetObject(){returnnewStudent();}OverridepublicClasslt;?getObjectType(){returnStudent。class;}}
  创建一个FactoryBean只需要实现其接口,并实现其中的两个方法。当我们获取FactoryBean时,会返回其中getObject()方法返回的对象。而如果想要获取FactoryBean本身,只需要在beanname前加一个符号即可。Resource()privateObjectfactoryBeanDemo;GetMapping(getStu)privateStringgetBean(){System。out。println(factoryBeanDemo。getClass());returnstu2。getName();}输出结果classcom。example。demo。domain。Student
  可以看到获取到的是Student类型。classcom。example。demo。spring。FactoryBeanDemo
  将获取bean名称假符号:Resource(namefactoryBeanDemo)privateObjectfactoryBeanDemo;classcom。example。demo。spring。FactoryBeanDemo
  可以看到获取到的对象变成了FactoryBeanDemo本身。2。2Bean注入流程
  在容器启动阶段,已经完成了bean的注册。如果该对象是配置成懒加载的方式,那么直到我们向Spring要依赖对象实例之前,其都是以BeanDefinitionRegistry中的一个个的BeanDefinition的形式存在,也就是Spring只有在我们第一次依赖对象的时候才开启相应对象的实例化阶段。而如果我们不是选择懒加载的方式,容器启动阶段完成之后,其中有一个步骤finishBeanFactoryInitialization(),在这一步将立即启动Bean实例化阶段,通过隐式的调用所有依赖对象的getBean方法来实例化所有配置的Bean,完成类的加载。
  doGetBean():获取并返回bean
  doGetBean()的主要流程有两个:尝试从缓存中获取bean,如果获取到直接返回。如果没有获取到则尝试加载bean。protectedTTdoGetBean(Stringname,NullableClassTrequiredType,NullableObject〔〕args,booleantypeCheckOnly)throwsBeansException{StringbeanNametransformedBeanName(name);ObjectbeanInstance;Eagerlychecksingletoncacheformanuallyregisteredsingletons。1、查询缓存中是否存在,存在的话直接返回ObjectsharedInstancegetSingleton(beanName);if(sharedInstance!nullargsnull){if(logger。isTraceEnabled()){if(isSingletonCurrentlyInCreation(beanName)){logger。trace(ReturningeagerlycachedinstanceofsingletonbeanbeanNamethatisnotfullyinitializedyetaconsequenceofacircularreference);}else{logger。trace(ReturningcachedinstanceofsingletonbeanbeanName);}}根据缓存中的bean获取实例,主要是检测如果是FactoryBean类型,则获取其内部的getObject()的bean。(需要先了解FactoryBean的作用)beanInstancegetObjectForBeanInstance(sharedInstance,name,beanName,null);}2、不存在则创建beanelse{Failifwerealreadycreatingthisbeaninstance:Wereassumablywithinacircularreference。if(isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName);}Checkifbeandefinitionexistsinthisfactory。2。1尝试从父类的Factory加载beanBeanFactoryparentBeanFactorygetParentBeanFactory();if(parentBeanFactory!null!containsBeanDefinition(beanName)){Notfoundcheckparent。StringnameToLookuporiginalBeanName(name);if(parentBeanFactoryinstanceofAbstractBeanFactory){return((AbstractBeanFactory)parentBeanFactory)。doGetBean(nameToLookup,requiredType,args,typeCheckOnly);}elseif(args!null){Delegationtoparentwithexplicitargs。return(T)parentBeanFactory。getBean(nameToLookup,args);}elseif(requiredType!null){NoargsdelegatetostandardgetBeanmethod。returnparentBeanFactory。getBean(nameToLookup,requiredType);}else{return(T)parentBeanFactory。getBean(nameToLookup);}}if(!typeCheckOnly){markBeanAsCreated(beanName);}StartupStepbeanCreationthis。applicationStartup。start(spring。beans。instantiate)。tag(beanName,name);try{if(requiredType!null){beanCreation。tag(beanType,requiredType::toString);}2。2获取RootBeanDefinition:首先会根据beanName获取BeanDefinition,然后将BeanDefinition转换为RootBeanDefinitionBeanDefinition接口的实现类有很多,通过不同方式注册到BeanDefinitionRegistry中的BeanDefinition的类型可能都不太相同。最终,在通过BeanDefinition来创建bean的实例时,通常都会调用getMergedBeanDefinition来获取到一个RootBeanDefinition。所以,RootBeanDefinition本质上是Spring运行时统一的BeanDefinition视图。RootBeanDefinitionmbdgetMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd,beanName,args);Guaranteeinitializationofbeansthatthecurrentbeandependson。2。3初始化依赖的beanString〔〕dependsOnmbd。getDependsOn();if(dependsOn!null){for(Stringdep:dependsOn){if(isDependent(beanName,dep)){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,CirculardependsonrelationshipbetweenbeanNameanddep);}registerDependentBean(dep,beanName);try{getBean(dep);}catch(NoSuchBeanDefinitionExceptionex){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,beanNamedependsonmissingbeandep,ex);}}}Createbeaninstance。2。4创建实例if(mbd。isSingleton()){sharedInstancegetSingleton(beanName,(){try{返回真正的beanreturncreateBean(beanName,mbd,args);}catch(BeansExceptionex){Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthereeagerlybythecreationprocess,toallowforcircularreferenceresolution。Alsoremoveanybeansthatreceivedatemporaryreferencetothebean。destroySingleton(beanName);throwex;}});beanInstancegetObjectForBeanInstance(sharedInstance,name,beanName,mbd);}}returnadaptBeanInstance(name,beanInstance,requiredType);}2。2。1mbdgetMergedLocalBeanDefinition(beanName)获取BeanDefinition
  RootBeanDefinitionmbdgetMergedLocalBeanDefinition(beanName);
  BeanDefinition接口的实现类有很多,通过不同方式注册到BeanDefinitionRegistry中的BeanDefinition的类型可能都不太相同。
  最终,在通过BeanDefinition来创建bean的实例时,通常都会调用getMergedBeanDefinition来获取到一个RootBeanDefinition。所以,RootBeanDefinition本质上是Spring运行时统一的BeanDefinition视图。
  此处就是将各种BeanDefinition统一转换为spring能识别的RootBeanDefinition。2。2。2getSingleton(StringbeanName,ObjectFactorylt;?singletonFactory)获取创建好的对象sharedInstancegetSingleton(beanName,(){try{返回真正的beanreturncreateBean(beanName,mbd,args);}catch(BeansExceptionex){Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthereeagerlybythecreationprocess,toallowforcircularreferenceresolution。Alsoremoveanybeansthatreceivedatemporaryreferencetothebean。destroySingleton(beanName);throwex;}});
  从getSingleton()方法中获取创建好的对象获取singletonFactory返回的结果singletonObjectsingletonFactory。getObject();
  getSingleton()方法中最主要的一次调用也就是从singletonFactory中获取对象,而获取对象的结果就是上面代码中传入的匿名工厂返回的结果,也就是createBean(beanName,mbd,args)2。2。3createBean(beanName,mbd,args)创建beanprotectedObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,NullableObject〔〕args)throwsBeanCreationException{if(logger。isTraceEnabled()){logger。trace(CreatinginstanceofbeanbeanName);}RootBeanDefinitionmbdToUsembd;Makesurebeanclassisactuallyresolvedatthispoint,andclonethebeandefinitionincaseofadynamicallyresolvedClasswhichcannotbestoredinthesharedmergedbeandefinition。1。解析beanclassClasslt;?resolvedClassresolveBeanClass(mbd,beanName);if(resolvedClass!null!mbd。hasBeanClass()mbd。getBeanClassName()!null){mbdToUsenewRootBeanDefinition(mbd);mbdToUse。setBeanClass(resolvedClass);}Preparemethodoverrides。2。准备覆盖的方法try{mbdToUse。prepareMethodOverrides();}catch(BeanDefinitionValidationExceptionex){thrownewBeanDefinitionStoreException(mbdToUse。getResourceDescription(),beanName,Validationofmethodoverridesfailed,ex);}try{GiveBeanPostProcessorsachancetoreturnaproxyinsteadofthetargetbeaninstance。3。尝试返回代理创建的Bean,这个作用就是查找bean中所有实现前置和后置处理器的接口,有没有手工创建然后返回的,代替了spring的创建bean的流程ObjectbeanresolveBeforeInstantiation(beanName,mbdToUse);if(bean!null){returnbean;}}catch(Throwableex){thrownewBeanCreationException(mbdToUse。getResourceDescription(),beanName,BeanPostProcessorbeforeinstantiationofbeanfailed,ex);}try{4。真正创建beanObjectbeanInstancedoCreateBean(beanName,mbdToUse,args);if(logger。isTraceEnabled()){logger。trace(FinishedcreatinginstanceofbeanbeanName);}returnbeanInstance;}catch(BeanCreationExceptionImplicitlyAppearedSingletonExceptionex){Apreviouslydetectedexceptionwithproperbeancreationcontextalready,orillegalsingletonstatetobecommunicateduptoDefaultSingletonBeanRegistry。throwex;}catch(Throwableex){thrownewBeanCreationException(mbdToUse。getResourceDescription(),beanName,Unexpectedexceptionduringbeancreation,ex);}}
  创建bean主要有以下几步:解析bean的class文件,为后面的根据class文件通过反射创建对象做准备。预处理bean的Override属性,预处理的方式也比较简单,就是在方法prepareMethodOverride中判断一下,如果lookupmethod标签或者replacedmethod标签中配置了bean中需要覆盖的方法,就将MethodOverride中的overload属性值设置为false。尝试通过反射获取被代理的bean。真正创建bean的过程2。2。4ObjectbeanInstancedoCreateBean(beanName,mbdToUse,args)开始创建bean
  以上流程都是获取bean前的流程或获取bean的准备,doCreateBean是真正的创建并填充bean的流程(去掉了一些不重要的代码)。protectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,NullableObject〔〕args)throwsBeanCreationException{Instantiatethebean。BeanWrapperinstanceWrappernull;if(mbd。isSingleton()){instanceWrapperthis。factoryBeanInstanceCache。remove(beanName);}if(instanceWrappernull){1。通过反射创建实例化对象,并将其放入wraaper中。wraaper可以理解为bean的包装对象,里面是bean实例的,还有一些其他bean的属性方便使用instanceWrappercreateBeanInstance(beanName,mbd,args);}ObjectbeaninstanceWrapper。getWrappedInstance();Classlt;?beanTypeinstanceWrapper。getWrappedClass();if(beanType!NullBean。class){mbd。resolvedTargetTypebeanType;}Allowpostprocessorstomodifythemergedbeandefinition。2。允许后处理处理器修改合并后的bean定义,这里只是解析这些AutowiredValueResourcePostConstruct等这些注解,并没有发生实际属性注入的动作synchronized(mbd。postProcessingLock){if(!mbd。postProcessed){try{applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName);}mbd。postProcessedtrue;}}EagerlycachesingletonstobeabletoresolvecircularreferencesevenwhentriggeredbylifecycleinterfaceslikeBeanFactoryAware。3。是否需要提前曝光,用来解决循环依赖时使用booleanearlySingletonExposure(mbd。isSingleton()this。allowCircularReferencesisSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){if(logger。isTraceEnabled()){logger。trace(EagerlycachingbeanbeanNametoallowforresolvingpotentialcircularreferences);}addSingletonFactory(beanName,()getEarlyBeanReference(beanName,mbd,bean));}Initializethebeaninstance。ObjectexposedObjectbean;4。将实例化完成成的bean填充属性populateBean(beanName,mbd,instanceWrapper);5。调用初始化方法,例如initmethodexposedObjectinitializeBean(beanName,exposedObject,mbd);6。循环依赖检查if(earlySingletonExposure){ObjectearlySingletonReferencegetSingleton(beanName,false);if(earlySingletonReference!null){if(exposedObjectbean){exposedObjectearlySingletonReference;}elseif(!this。allowRawInjectionDespiteWrappinghasDependentBean(beanName)){String〔〕dependentBeansgetDependentBeans(beanName);SetStringactualDependentBeansnewLinkedHashSet(dependentBeans。length);for(StringdependentBean:dependentBeans){if(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)){actualDependentBeans。add(dependentBean);}}}}}Registerbeanasdisposable。7。注册beantry{registerDisposableBeanIfNecessary(beanName,bean,mbd);}catch(BeanDefinitionValidationExceptionex){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,Invaliddestructionsignature,ex);}returnexposedObject;}
  从上述流程中可以看到,我们创建一个bean主要有以下几个流程:首先通过class根据反射创建对象,此时该对象的所有的属性都为空,可以理解为我们new出的空属性对象。解析AutowiredValueResourcePostConstruct这些注解,但并没有发生属性注入的行为。是否需要提前曝光,用来解决循环依赖时使用,主要作用是如果需要代理会返回代理对象,如果不需要代理,返回前面创建的对象将第一步实例化完成的空属性对象填充属性,其中如果该bean依赖了其他bean,也会在此步骤将依赖的bean装配,如果bean已经被创建,则直接属性注入,如果不存在,则创建bean,创建方式跟本bean相同,可以理解为递归。将实例化完成的bean对象初始化,主要查看bean是否实现了一些前置或后置或初始化的方法,如果是的话就执行。循环依赖检查。根据scope注册bean。
  可以看到,经过以上的几个步骤,我们就获取到了一个实例bean。
  其中最重要的三个方法:实例化bean装配属性初始化bean2。2。5总结
  总结来说,创建bean的流程就是先根据反射获取对象,然后填充对象的属性,初始化,最后将bean注册。
  2。3创建bean流程深入理解
  上文我们只粗略的讲解了创建bean的过程,并没有深入的查看源码是如何实现的,例如通过反射获取对象是怎么获取的,填充属性是如何填充的,下文将详细阐述2。2。5过程中在源码层面是如何构建的。2。3。1instanceWrappercreateBeanInstance(beanName,mbd,args)获取实例化对象
  该方法通过反射获取实例化的空属性对象。protectedBeanWrappercreateBeanInstance(StringbeanName,RootBeanDefinitionmbd,NullableObject〔〕args){Makesurebeanclassisactuallyresolvedatthispoint。1。1解析classClasslt;?beanClassresolveBeanClass(mbd,beanName);1。2确认public权限if(beanClass!null!Modifier。isPublic(beanClass。getModifiers())!mbd。isNonPublicAccessAllowed()){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,Beanclassisntpublic,andnonpublicaccessnotallowed:beanClass。getName());}2。如果存在Supplier回调,则调用obtainFromSupplier()进行初始化,因为反射获取对象的效率比较低Supplierlt;?instanceSuppliermbd。getInstanceSupplier();if(instanceSupplier!null){returnobtainFromSupplier(instanceSupplier,beanName);}if(mbd。getFactoryMethodName()!null){returninstantiateUsingFactoryMethod(beanName,mbd,args);}Shortcutwhenrecreatingthesamebean。。。booleanresolvedfalse;booleanautowireNecessaryfalse;if(argsnull){synchronized(mbd。constructorArgumentLock){3。如果args为空且方法已经被resolved,则会直接选择对应的构造方法mbd。resolvedConstructorOrFactoryMethod的赋值在下方【1】【2】的代码中赋值if(mbd。resolvedConstructorOrFactoryMethod!null){resolvedtrue;autowireNecessarymbd。constructorArgumentsResolved;}}}if(resolved){if(autowireNecessary){returnautowireConstructor(beanName,mbd,null,null);}else{returninstantiateBean(beanName,mbd);}}Candidateconstructorsforautowiring?4。自动装配的构造方法Constructorlt;?〔〕ctorsdetermineConstructorsFromBeanPostProcessors(beanClass,beanName);if(ctors!nullmbd。getResolvedAutowireMode()AUTOWIRECONSTRUCTORmbd。hasConstructorArgumentValues()!ObjectUtils。isEmpty(args)){returnautowireConstructor(beanName,mbd,ctors,args);}Preferredconstructorsfordefaultconstruction?5。是否有首选构造方法ctorsmbd。getPreferredConstructors();if(ctors!null){returnautowireConstructor(beanName,mbd,ctors,null);}Nospecialhandling:simplyusenoargconstructor。6。通过默认的无参构造函数returninstantiateBean(beanName,mbd);}首先解析class文件与确认public权限。如果存在Supplier回调,则调用obtainFromSupplier()进行初始化,因为反射获取对象的效率比较低。如果args为空且使用那个构造函数已经被确定了,则进行标记,后续直接选择使用那种构造方法。如果args不为空或没有被解析过,则选择使用那种构造方法来构造实例化的对象:
  Constructorlt;?〔〕ctorsdetermineConstructorsFromBeanPostProcessors(beanClass,beanName);
  Constructorlt;?〔〕ctorsbp。determineCandidateConstructors(beanClass,beanName);
  选择AutowiredAnnotationBeanPostProcessor实现类:
  其中重要的代码已贴出:1。遍历所有的构造方法for(Constructorlt;?candidate:rawCandidates){if(!candidate。isSynthetic()){nonSyntheticConstructors;}elseif(primaryConstructor!null){continue;}2。查看当前构造方法是否有Autowired注解MergedAnnotationlt;?annfindAutowiredAnnotation(candidate);if(annnull){Classlt;?userClassClassUtils。getUserClass(beanClass);if(userClass!beanClass){try{Constructorlt;?superCtoruserClass。getDeclaredConstructor(candidate。getParameterTypes());annfindAutowiredAnnotation(superCtor);}catch(NoSuchMethodExceptionex){Simplyproceed,noequivalentsuperclassconstructorfound。。。}}}3。如果有Autowired注解if(ann!null){4。如果已经有一个Autowired注解,则说明存在多个Autowired注解,则抛出异常if(requiredConstructor!null){thrownewBeanCreationException(beanName,Invalidautowiremarkedconstructor:candidate。FoundconstructorwithrequiredAutowiredannotationalready:requiredConstructor);}booleanrequireddetermineRequiredStatus(ann);if(required){if(!candidates。isEmpty()){thrownewBeanCreationException(beanName,Invalidautowiremarkedconstructors:candidates。FoundconstructorwithrequiredAutowiredannotation:candidate);}requiredConstructorcandidate;}candidates。add(candidate);}5无参构造函数elseif(candidate。getParameterCount()0){将其设置为默认构造函数defaultConstructorcandidate;}}对上面的处理过程进行判断6。1先检查是否有Autowired注解if(!candidates。isEmpty()){Adddefaultconstructortolistofoptionalconstructors,asfallback。if(requiredConstructornull){if(defaultConstructor!null){candidates。add(defaultConstructor);}elseif(candidates。size()1logger。isInfoEnabled()){logger。info(InconsistentconstructordeclarationonbeanwithnamebeanName:singleautowiremarkedconstructorflaggedasoptionalthisconstructoriseffectivelyrequiredsincethereisnodefaultconstructortofallbackto:candidates。get(0));}}返回Autowired注解的构造方法candidateConstructorscandidates。toArray(newConstructorlt;?〔0〕);}6。2如果只有一个有参构造函数,则返回该有参函数elseif(rawCandidates。length1rawCandidates〔0〕。getParameterCount()0){candidateConstructorsnewConstructorlt;?〔〕{rawCandidates〔0〕};}6。3对于非Kotlin类只会返回null,所以这里不会进入elseif(nonSyntheticConstructors2primaryConstructor!nulldefaultConstructor!null!primaryConstructor。equals(defaultConstructor)){candidateConstructorsnewConstructorlt;?〔〕{primaryConstructor,defaultConstructor};}elseif(nonSyntheticConstructors1primaryConstructor!null){candidateConstructorsnewConstructorlt;?〔〕{primaryConstructor};}else{6。4对于不能识别的场景会进入到这里,例如有多个构造函数但是并没有指定Autowired注解或者没有构造函数(java会帮我们生成一个无参的构造函数),返回nullcandidateConstructorsnewConstructorlt;?〔0〕;}
  25步会对所有的构造函数进行检查,并在检查完进行标记,并会在第6步对标记的结果进行返回,按照ifelse判断顺序主要分为以下几种情况:如果有Autowired注解的方法则返回该构造方法如果只有一个有参构造函数则会返回该有参构造函数对于不能识别的场景会进入到这里,例如有多个构造函数但是并没有指定Autowired注解或者没有构造函数(java会帮我们生成一个无参的构造函数)会返回null
  在获取到需要的构造函数后,会进行标记,下次不用再次解析可以直接选用那个构造函数,即上文的第4步是否有首选的构造函数如果都没有的话,通过默认的无参构造函数创建对象。
  我们查看代码发现,无论第4步返回什么结果,最终会执行以下两个方法:
  autowireConstructor()与instantiateBean()
  两者都会调用
  instantiate()方法
  最终都会执行以下这个方法
  BeanUtils。instantiateClass(constructorToUse)
  也就是如下的代码for(inti0;iargs。length;i){if(args〔i〕null){Classlt;?parameterTypeparameterTypes〔i〕;argsWithDefaultValues〔i〕(parameterType。isPrimitive()?DEFAULTTYPEVALUES。get(parameterType):null);}else{argsWithDefaultValues〔i〕args〔i〕;}}returnctor。newInstance(argsWithDefaultValues);
  其中最重要的一句:
  returnctor。newInstance(argsWithDefaultValues);
  可以发现,也就是这里通过反射的方式创建了一个空属性对象,并一层层返回,直到后面的属性装配等过程,可以说这里就是bean加载过程的源头。2。3。2applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName)解析各种注解
  该方法主要解析该bean所相关的注解,例如属性有Resource,bean中PostConstruct注解都会被解析。for(MergedBeanDefinitionPostProcessorprocessor:getBeanPostProcessorCache()。mergedDefinition){processor。postProcessMergedBeanDefinition(mbd,beanType,beanName);}
  processor主要有两个实现类:AutowiredAnnotationBeanPostProcessor处理Autowired和Value注解bean定义信息CommonAnnotationBeanPostProcessor处理Resource、PostConstruct、PreDestroy注解的bean定义信息
  这里需要注意的是,该方法只是会解析并不会真正的进行注入,因为学习意义不大,并不在赘述。2。3。3populateBean(beanName,mbd,instanceWrapper)对实例化完成的bean进行属性注入遍历所有的属性for(InstantiationAwareBeanPostProcessorbp:getBeanPostProcessorCache()。instantiationAware){对属性进行装填PropertyValuespvsToUsebp。postProcessProperties(pvs,bw。getWrappedInstance(),beanName);if(pvsToUsenull){if(filteredPdsnull){filteredPdsfilterPropertyDescriptorsForDependencyCheck(bw,mbd。allowCaching);}pvsToUsebp。postProcessPropertyValues(pvs,filteredPds,bw。getWrappedInstance(),beanName);if(pvsToUsenull){return;}}pvspvsToUse;}
  其中bp。postProcessProperties(pvs,bw。getWrappedInstance(),beanName)有几个实现方法,比较重要的是:AutowiredAnnotationBeanPostProcessor,主要装配属性是Autowired与Value的属性CommonAnnotationBeanPostProcessor,主要装配属性是Resource的属性
  两者最终都会进入如下方法:判断要注入的是属性还是方法if(this。isField){Fieldfield(Field)this。member;ReflectionUtils。makeAccessible(field);如果是属性的话则直接注入field。set(target,getResourceToInject(target,requestingBeanName));}else{if(checkPropertySkipping(pvs)){return;}try{Methodmethod(Method)this。member;ReflectionUtils。makeAccessible(method);否则通过反射注入method。invoke(target,getResourceToInject(target,requestingBeanName));}catch(InvocationTargetExceptionex){throwex。getTargetException();}}
  理解起来比较简单,判断是方法注入还是属性注入,在注入时注入的对象为:
  getResourceToInject(target,requestingBeanName)
  找到ResourceElement的实现方法中getResource()方法:
  返回了autowireResource(this。resourceFactory,element,requestingBeanName)if(factoryinstanceofAutowireCapableBeanFactory){AutowireCapableBeanFactorybeanFactory(AutowireCapableBeanFactory)factory;DependencyDescriptordescriptorelement。getDependencyDescriptor();if(this。fallbackToDefaultTypeMatchelement。isDefaultName!factory。containsBean(name)){autowiredBeanNamesnewLinkedHashSet();resourcebeanFactory。resolveDependency(descriptor,requestingBeanName,autowiredBeanNames,null);if(resourcenull){thrownewNoSuchBeanDefinitionException(element。getLookupType(),Noresolvableresourceobject);}}else{resourcebeanFactory。resolveBeanByName(name,descriptor);autowiredBeanNamesCollections。singleton(name);}}else{resourcefactory。getBean(name,element。lookupType);autowiredBeanNamesCollections。singleton(name);}
  在这个方法中,无论是if还是else,最终都会调用getBean(name,element。lookupType)
  也就是我们bean注入的入口,这个过程很像递归,在我们创建bean时,如果发现我们有依赖的其他bean,那么就会去创建依赖的bean,如果依赖的bean还有其依赖的属性则又会去创建被依赖的属性,只到最终全部创建完成,返回一开始想要创建的bean。2。3。4exposedObjectinitializeBean(beanName,exposedObject,mbd)初始化bean
  在该方法中,会对已经填充过属性的bean进行初始化:ObjectwrappedBeanbean;if(mbdnull!mbd。isSynthetic()){对bean的前置处理,其中PostConstruct就在此步骤中wrappedBeanapplyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName);}try{调用初始化方法如果bean实现了InitializingBean接口,则先执行InitializingBean接口的afterPropertiesSet方法,然后执行xml或注解设置的initmethod方法。invokeInitMethods(beanName,wrappedBean,mbd);}catch(Throwableex){thrownewBeanCreationException((mbd!null?mbd。getResourceDescription():null),beanName,Invocationofinitmethodfailed,ex);}if(mbdnull!mbd。isSynthetic()){对bean进行后置处理,对象的代理发生在此步骤中wrappedBeanapplyBeanPostProcessorsAfterInitialization(wrappedBean,beanName);}
  在初始化bean的时候,主要分为三个部分,分别是applyBeanPostProcessorsBeforeInitialization、invokeInitMethods、applyBeanPostProcessorsAfterInitialization,分别对应于初始化的前置处理、自定义init方法、后置处理。
  applyBeanPostProcessorsBeforeInitialization、applyBeanPostProcessorsAfterInitialization两个方法的大概逻辑就是获取获取所有实现其接口的类,然后执行其中被覆盖的方法。
  常用的注解执行顺序如下:PostConstruct注解修饰的方法InitializingBean接口的afterPropertiesSet()方法initmethod指定的方法PreDestroy注解修饰的方法DisposableBean接口的destroy()方法destorymethod指定的方法
  并且在代码中可以看到,前置处理与后置处理都可以改变bean。在容器启动阶段我们讲到BeanFactoryPostProcessor,这里我们讲到BeanPostProcessor,那么BeanFactoryPostProcessor和BeanPostProcessor有什么区别呢?
  BeanFactoryPostProcessor存在于容器启动阶段,而BeanPostProcessor存在于对象实例化阶段,BeanFactoryPostProcessor关注对象被创建之前那些配置的修改,而BeanPostProcessor阶段关注对象已经被创建之后的功能增强,替换等操作,这样就很容易区分了。
  BeanPostProcessor与BeanFactoryPostProcessor都是Spring在Bean生产过程中强有力的扩展点。Spring中著名的AOP(面向切面编程),其实就是依赖BeanPostProcessor对Bean对象功能增强的。
  BeanFactoryPostProcessor主要用于解决实例化之前,对实例的属性进行拓展,而BeanPostProcessor是在实例化之后对对象做的拓展。2。4总结
  用简单的话描述一下,创建一个bean的过程大概包括三部分:通过反射实例化bean属性装配以及填充初始化,包括initmethod、以及其前后三个步骤。其中AOP增强就是发生在初始化之后的applyBeanPostProcessorsAfterInitialization的步骤中。
  通过以上的步骤,就可以获得我们可以正常使用的一个bean。

广东宏远崛起之路应该如何进行?广东宏远再度起航曾经的八冠王广东宏远队,在休赛期再度起航,以朱芳雨为首的管理层积极赴美考察球员,以为广东宏远作最强的补充。近日,广东宏远官宣签约前北京队外援莫里斯。这个是大新闻,出现在还建议买iPadpro9。7吗?多谢邀请。iPadPro10。5发布之后,iPadPro9。7已经不值得去关注。虽然后者比前者在一些渠道上的价格要低一些,不过并没有特别大的优势,况且10。5的提升蛮多,是关注的首怎么清理助听器的喇叭和麦克风?助听器属于精密的电子产品,自己的护理需要有验配师指导以后进行比较好哦,一般正常在家的话基本上只要清洁外壳,以及助听器出声口的地方基本上就可以了,麦克风不是经常需要清理的,可以在验配退休老人手里有20万存款,是不是感到养老的底气不足了?如果你去大街上做个街访,随便问一个过路人20万的银行存款,算不算大钱?能不能让人有底气的活着?估计十个人有九个都会回答你20万银行存款,当然不算什么大钱。甚至可能会有人告诉你,202020年,双一流b类高校经费情况怎么样?谁是第一,谁是倒数第一?大学怎么发展?靠什么?底蕴?历史?文化?其实都错了,大学的发展靠的是人才,靠的是大楼,最终这些归根结底都是一个东西钱,有钱不是万能的,但是没有钱是万万不能的。不论是办大学还是招员工戴耳背式助听器为什么要配耳膜?耳背式助听器配耳模,这个看听力情况或者看你配戴的普通耳塞合不合适,验配师会根据你的配戴效果决定要不要配耳模。耳模主要有三个功能,一是固定助听器,二是把助听器放大后的声音传入耳内,起为什么有些适合双耳佩戴助听器的患者最终只选择一个助听器?1。经济原因助听器价格高,不能接受。2。听力不对等一侧听损轻,另一侧较重,双耳佩戴后的清晰度和舒适度不如单耳佩戴效果好。3。佩戴不适应可以先选配一边适应,适应后尽快选配另一边您好,助听器能左右耳佩戴吗?助听器有几种类型的,如果是简单的模拟助听器,是不区分左右耳,两侧都是可以直接佩戴的。不过现在主流市场的助听器都是数字助听器,是要测试听损患者的听力损失,根据听力损失和听觉反映调试助一个耳朵有听力损失需要配助听器吗?一侧耳听力正常,一侧听力受损,仍需配戴助听器,人的双耳听力不对称时,听觉系统就会依赖性地分析和处理听力较好耳扑捉到的声音信息,而较差耳因得不到听觉和系统重用可能会丧失听觉方面的能力9月13号做的清宫手术,月经干净第5天复查,竟然有个子宫肌瘤,该怎么办?谢邀妊娠期因为子宫增大胎儿的影响,容易导致小的子宫肌瘤难以被超声探查到。月经干净后,子宫恢复原来大小,一些小的子宫肌瘤容易被探查到,如果是小的肌壁间或者浆膜下肌瘤一般不会引起流产,儿童助听器为什么要用耳模?1836个月,6个月更换一次36岁,9个月到1年更换一次。作用是1)固定助听器耳模最基本的作用是可以使助听器的佩戴更加稳固舒适。由于耳膜是完全依照耳廓和外耳道的形状制成,耳轮耳甲腔
自动驾驶蓄势待发,车企如何拥抱智能化本文概述8月1日,中国首部智能网联汽车管理法规在深圳正式生效,深圳由此成为第一个允许全无人自动驾驶汽车上路的城市。这一政策使行业人士感到振奋,L3自动驾驶落地的曙光开始显现。新规的鸿海发布两款新电动车ModelBModelV,后者定位电动皮卡IT之家10月18日消息,今日在富士康母公司鸿海精密工业股份有限公司科技日上,鸿海董事长刘扬伟今天驾着量产版ModelC电动车款为鸿海科技日揭开序幕,科技日同时发布ModelB和M雷军孤注一掷,小米12Pro降价1700元,又亲民厚道了小米这个手机品牌在做新机的时候都习惯性地要先听取米粉们的建议,比如当初发布小米12系列之前,雷军等人就问了米粉们关于尺寸上的建议,很多米粉表示希望在小米12系列中能看到小屏旗舰。为iPhoneSE4渲染图三千元价位无敌手,苹果再次收割果粉血汗钱iPhone14系列发布之后,按照苹果传统的设计思路,独立的iPhoneSE系列也会继续发布。iPhoneSE系列的定位是三千元价格区间,为什么不和苹果的数字系列同时发布,主要原因围棋王子常昊不顾恩师反对,娶大8岁二婚师姑,现状如何?1999年春节前夕,在国际上赫赫有名的围棋王子常昊和刚刚夺得世界冠军的围棋才女张璇步入了婚姻的殿堂。值得一提的是,常昊比张璇小八岁,两人第一次见面时,常昊才10岁。对于常昊来说,张足坛四大玄学教练圣光护体,运气爆棚,个个是国足主帅候选诗云口渴路遇山泉水,瞌睡有人送枕头。屎顶肛门遇公厕,两腿蹲麻捡手纸。这个世界上总有这么一波人,仿佛圣光护体,顺风顺水青云直上,干什么成什么,他们运气好到爆,完全无法用科学来解释。于巴克利10年2亿美金续约TNT解说员,比打NBA赚的还要多出5倍近日,有媒体爆料TNT解说员巴克利即将获得一份新的合同,这份新合同的期限为十年,金额最高可以达到2亿美金。着实有些羡煞旁人,巴特利的这份薪资可以说超过了现役90的NBA球员。巴克利奇瑞新能源硬派SUV曝光与捷途T1近似日前,网络上曝光了一款奇瑞新能源硬派SUV效果图,其外观与目前已经亮相的捷途T1外观高度相似,但细节上仍有很大的不同,意味着在燃油车型之后,奇瑞可能还将出一款新能源硬派SUV。从效郭艾伦提前锁定无缘本赛季MVP10月18日CBA官网发布公告。公告内容大致情况是辽宁队队员郭艾伦助力教练柴长易队员俞泽辰因违反赛区安全管理规定和赛风赛纪承诺书的有关规定。对涉事球员和教练做出处罚。郭艾伦罚款10今日水素轻生活护肺应该做这些事肺是人体重要的呼吸器官,是人体进行气体交换的重要场所,通过肺的呼吸作用,人体呼出浊气,吸入新鲜空气,从而保证生命的正常运转。中医认为肺主一身之气,主行水,调节人体的水液代谢。肺的重健脾和补脾是一回事儿吗?你到底该健脾还是补脾呢?现代人的脾胃都比较差,经常会出现腹痛腹胀腹泻便秘等消化不良的症状,本着缺什么补什么的原则,大家首先想到的就是补脾,结果食补药补补了半天,效果并不明显,有的甚至越补越差。这是为什么呢
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网