Spring源碼:bean的生命周期(一)_第1頁
Spring源碼:bean的生命周期(一)_第2頁
Spring源碼:bean的生命周期(一)_第3頁
Spring源碼:bean的生命周期(一)_第4頁
Spring源碼:bean的生命周期(一)_第5頁
已閱讀5頁,還剩13頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第Spring源碼:bean的生命周期(一)本節(jié)將正式介紹Spring源碼細(xì)節(jié),將講解Bean生命周期。請(qǐng)注意,雖然我們不希望過于繁瑣地理解Spring源碼,但也不要認(rèn)為Spring源碼很簡(jiǎn)單。在本節(jié)中,我們將主要講解Spring5.3.10版本的源代碼。如果您看到的代碼與我講解的不同,也沒有關(guān)系,因?yàn)槠渲械脑砗蜆I(yè)務(wù)邏輯基本相同。為了更好地理解,我們將先講解Bean的生命周期,再講解Spring的啟動(dòng)原理和流程,因?yàn)閱?dòng)是準(zhǔn)備工作的一部分。

目前在該版本中,引入了一個(gè)名為jfr的JDK技術(shù),類似于Java飛行日志(JFL),也稱為飛行數(shù)據(jù)記錄器(BlackBox)技術(shù)。具體作用不再詳細(xì)闡述,讀者可以參考此文:JFR介紹

如果您看到以下代碼,請(qǐng)直接跳過,因?yàn)樗]有太大的作用:

publicAnnotationConfigApplicationContext(){

StartupStepcreateAnnotatedBeanDefReader=this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");

//額外會(huì)創(chuàng)建StandardEnvironment

this.reader=newAnnotatedBeanDefinitionReader(this);

createAnnotatedBeanDefReader.end();

this.scanner=newClassPathBeanDefinitionScanner(this);

需要注意的是,其中的StartupStep關(guān)于默認(rèn)實(shí)現(xiàn)并沒有什么實(shí)際作用。但是,還有一種實(shí)現(xiàn)方式是FlightRecorderStartupStep,它是JDK的JFR技術(shù)。

Bean的生成過程

生成BeanDefinition

BeanDefinition的作用大家基本通過前面的文章也知道了大概,就是用來描述bean的。

那么它是如何加載的呢?首先我們看一下ClassPathBeanDefinitionScanner類,它是用于掃描的。其中有一個(gè)屬性是BeanDefinitionRegistry,即Bean定義的注冊(cè)類。默認(rèn)實(shí)現(xiàn)是DefaultListableBeanFactory,但是在ClassPathBeanDefinitionScanner類中并沒有直接使用該類作為屬性,而是使用了它的父接口BeanDefinitionRegistry。這是因?yàn)镃lassPathBeanDefinitionScanner類實(shí)際上并沒有使用BeanDefinitionRegistry接口中的許多方法來注冊(cè)Bean定義。

接下來,我們來分析ClassPathBeanDefinitionScanner類的scan方法:

protectedSetBeanDefinitionHolderdoScan(String...basePackages){

Assert.notEmpty(basePackages,"Atleastonebasepackagemustbespecified");

SetBeanDefinitionHolderbeanDefinitions=newLinkedHashSet();

for(StringbasePackage:basePackages){

SetBeanDefinitioncandidates=findCandidateComponents(basePackage);

for(BeanDefinitioncandidate:candidates){

ScopeMetadatascopeMetadata=this.scopeMetadataResolver.resolveScopeMetadata(candidate);

candidate.setScope(scopeMetadata.getScopeName());

StringbeanName=this.beanNameGenerator.generateBeanName(candidate,this.registry);

if(candidateinstanceofAbstractBeanDefinition){

postProcessBeanDefinition((AbstractBeanDefinition)candidate,beanName);

if(candidateinstanceofAnnotatedBeanDefinition){

//解析@Lazy、@Primary、@DependsOn、@Role、@Description

AnnotationConfigUcessCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);

//檢查Spring容器中是否已經(jīng)存在該beanName

if(checkCandidate(beanName,candidate)){

BeanDefinitionHolderdefinitionHolder=newBeanDefinitionHolder(candidate,beanName);

definitionHolder=

AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder,this.registry);

beanDefinitions.add(definitionHolder);

//注冊(cè)

registerBeanDefinition(definitionHolder,this.registry);

returnbeanDefinitions;

大致邏輯如下:

獲取掃描包路徑

findCandidateComponents:獲取符合條件的bean

遍歷candidate(候選bean),由于第二部使用了ASM技術(shù),所以并沒有真正獲取beanclass而是使用了beanname替代所以,遍歷的做法就是將符合條件的bean定義進(jìn)行注冊(cè)。

scopeMetadata解析scope注解。

beanNameGenerator構(gòu)建當(dāng)前bean的唯一名字。

postProcessBeanDefinition這里其實(shí)就是進(jìn)行默認(rèn)值賦值。

processCommonDefinitionAnnotations進(jìn)行解析@Lazy、@Primary、@DependsOn、@Role、@Description

checkCandidate(beanName,candidate)再次檢查是否該beanName已經(jīng)注冊(cè)過。

registerBeanDefinition,注冊(cè)到我們的DefaultListableBeanFactory的BeanDefinitionMap中。

其實(shí)這里基本就已經(jīng)大概了解的差不多了,然后再繼續(xù)講解下每一個(gè)流程里面都走了那些邏輯:

findCandidateComponents

其主要邏輯會(huì)進(jìn)入如下源碼:

privateSetBeanDefinitionscanCandidateComponents(StringbasePackage){

SetBeanDefinitioncandidates=newLinkedHashSet();

try{

//獲取basePackage下所有的文件資源

StringpackageSearchPath=ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX+

resolveBasePackage(basePackage)+'/'+this.resourcePattern;

Resource[]resources=getResourcePatternResolver().getResources(packageSearchPath);

booleantraceEnabled=logger.isTraceEnabled();

booleandebugEnabled=logger.isDebugEnabled();

for(Resourceresource:resources){

if(traceEnabled){

logger.trace("Scanning"+resource);

if(resource.isReadable()){

try{

MetadataReadermetadataReader=getMetadataReaderFactory().getMetadataReader(resource);

//excludeFilters、includeFilters判斷

if(isCandidateComponent(metadataReader)){//@Component--includeFilters判斷

ScannedGenericBeanDefinitionsbd=newScannedGenericBeanDefinition(metadataReader);

sbd.setSource(resource);

if(isCandidateComponent(sbd)){

if(debugEnabled){

logger.debug("Identifiedcandidatecomponentclass:"+resource);

candidates.add(sbd);

//此處省略部分代碼

......

returncandidates;

讓我們來深入了解一下Bean掃描的具體細(xì)節(jié)。以下是主要流程:

獲取basePackage下所有的文件資源。以下分析注解信息等都是用到了ASM技術(shù),并沒有真正的去加載這個(gè)類。

isCandidateComponent(metadataReader),進(jìn)行判斷是否當(dāng)前類具有@component注解。

isCandidateComponent(sbd),進(jìn)行判斷是否當(dāng)前類屬于內(nèi)部類、接口、抽象類

符合上述條件則會(huì)加入到bean定義候選集合中。

ASM技術(shù)這里不做多解釋,主要看下Spring是如何進(jìn)行判斷校驗(yàn)當(dāng)前bean是否符合條件的,第一個(gè)isCandidateComponent(metadataReader)方法:

protectedbooleanisCandidateComponent(MetadataReadermetadataReader)throwsIOException{

for(TypeFiltertf:this.excludeFilters){

if(tf.match(metadataReader,getMetadataReaderFactory())){

returnfalse;

//符合includeFilters的會(huì)進(jìn)行條件匹配,通過了才是Bean,也就是先看有沒有@Component,再看是否符合@Conditional

for(TypeFiltertf:this.includeFilters){

if(tf.match(metadataReader,getMetadataReaderFactory())){

returnisConditionMatch(metadataReader);

returnfalse;

那么includeFilters默認(rèn)會(huì)在啟動(dòng)AnnotationConfigApplicationContext時(shí)就會(huì)默認(rèn)注冊(cè)一個(gè)解析Component注解的filter,代碼如下:

protectedvoidregisterDefaultFilters(){

//注冊(cè)@Component對(duì)應(yīng)的AnnotationTypeFilter

this.includeFilters.add(newAnnotationTypeFilter(Component.class));

ClassLoadercl=ClassPathScanningCandidateComponentProvider.class.getClassLoader();

try{

this.includeFilters.add(newAnnotationTypeFilter(

((ClassextendsAnnotation)ClassUtils.forName("javax.annotation.ManagedBean",cl)),false));

logger.trace("JSR-250'javax.annotation.ManagedBean'foundandsupportedforcomponentscanning");

catch(ClassNotFoundExceptionex){

//JSR-2501.1API(asincludedinJavaEE6)notavAIlable-simplyskip.

try{

this.includeFilters.add(newAnnotationTypeFilter(

((ClassextendsAnnotation)ClassUtils.forName("javax.inject.Named",cl)),false));

logger.trace("JSR-330'javax.inject.Named'annotationfoundandsupportedforcomponentscanning");

catch(ClassNotFoundExceptionex){

//JSR-330APInotavailable-simplyskip.

如果符合過濾條件,那么他就會(huì)開始生成最初的bean定義:

publicScannedGenericBeanDefinition(MetadataReadermetadataReader){

Assert.notNull(metadataReader,"MetadataReadermustnotbenull");

this.metadata=metadataReader.getAnnotationMetadata();

//這里只是把className設(shè)置到BeanDefinition中

setBeanClassName(this.metadata.getClassName());

setResource(metadataReader.getResource());

那么就剩下最后的校驗(yàn)了:isCandidateComponent(sbd);再來看看他的作用子什么:

protectedbooleanisCandidateComponent(AnnotatedBeanDefinitionbeanDefinition){

AnnotationMetadatametadata=beanDefinition.getMetadata();

return(metadata.isIndependent()(metadata.isConcrete()||

(metadata.isAbstract()metadata.hasAnnotatedMethods(Lookup.class.getName()))));

看完一臉懵,那我們就好好解釋一下每個(gè)判斷都是什么意思吧:

metadata.isIndependent():是否當(dāng)前類為內(nèi)部類,眾說周知java語言編譯內(nèi)部類的時(shí)候會(huì)產(chǎn)生兩個(gè)class文件,比如下面這樣:

那么這個(gè)Member內(nèi)部類是不會(huì)被Spring作為單獨(dú)的類去掃描的。除非也加上@component注解,并且為static內(nèi)部類

metadata.isConcrete():這個(gè)類就是判斷下是否是接口還是抽象類

metadata.hasAnnotatedMethods(Lookup.class.getName()):判斷是否有方法是帶有Lookup注解的,Lookup注解工作中用到的確實(shí)有些少,我在這里簡(jiǎn)要說明下:比如我們注冊(cè)給Spring的bean都是單例,但是如果我們有多例的bean被一個(gè)單例的bean所依賴的話,一次屬性只能注入一次,也打不到多例的效果,這時(shí)候就可以用Lookup注解實(shí)現(xiàn)了,比如這樣:

AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext(AppConfig.class);

//UserService為單例

UserServicebean=applicationContext.getBean(UserService.class);

bean.test();

bean.test();

@Component

publicclassUserService{

@Autowired

privateUseruser;

publicvoidtest(){

System.out.println(user);

@Component

@Scope("prototype")

publicclassUser{

如果這樣執(zhí)行的話,你永遠(yuǎn)拿不到多例的User類,因?yàn)閁serService在屬性依賴注入的時(shí)候已經(jīng)做完了賦值,每次調(diào)用拿到的都是同一個(gè)對(duì)象,那如果不這么做可不可以,當(dāng)然可以:比如這樣改下UserService類:

@Component

publicclassUserService{

@Autowired

privateUseruser;

publicvoidtest(){

System.out.println(get());

@Lookup

publicUserget(){

returnnull;

至于為什么這里返回null,后續(xù)在進(jìn)行講解,只要知道他的注解的作用即可。到此我們終于解決完了findCandidateComponents方法找出了符合條件的bean定義。

generateBeanName

獲取當(dāng)前bean的beanname,源碼如下:

publicStringgenerateBeanName(BeanDefinitiondefinition,BeanDefinitionRegistryregistry){

if(definitioninstanceofAnnotatedBeanDefinition){

//獲取注解所指定的beanName

StringbeanName=determineBeanNameFromAnnotation((AnnotatedBeanDefinition)definition);

if(StringUtils.hasText(beanName)){

//Explicitbeannamefound.

returnbeanName;

//Fallback:generateauniquedefaultbeanname.

returnbuildDefaultBeanName(definition,registry);

buildDefaultBeanName構(gòu)建注解我們寫beanname這個(gè)不難理解,如果沒有那么就會(huì)走默認(rèn)的構(gòu)建,那么這里是jdk提供的,有個(gè)點(diǎn)需要注意下如果首字母和第二個(gè)字母都是大寫那么名字直接return,如果你寫的是ABtest,那么beanname就是ABtest:

publicstaticStringdecapitalize(Stringname){

if(name==null||name.length()==0){

returnname;

if(name.length()1Character.isUpperCase(name.charAt(1))

Character.isUpperCase(name.charAt(0))){

returnname;

charchars[]=name.toCharArray();

chars[0]=Character.toLowerCase(chars[0]);

returnnewString(chars);

postProcessBeanDefinition

這里主要是進(jìn)行設(shè)置BeanDefinition的默認(rèn)值,直接看源碼就能看懂:

publicvoidapplyDefaults(BeanDefinitionDefaultsdefaults){

BooleanlazyInit=defaults.getLazyInit();

if(lazyInit!=null){

setLazyInit(lazyInit);

setAutowireMode(defaults.getAutowireMode());

setDependencyCheck(defaults.getDependencyCheck());

setInitMethodName(defaults.getInitMethodName());

setEnforceInitMethod(false);

setDestroyMethodName(defaults.getDestroyMethodName());

setEnforceDestroyMethod(false);

processCommonDefinitionAnnotations

這一步主要時(shí)進(jìn)行解析類上的注解,看源碼也可以基本看懂,沒有太多繞的邏輯,如下展示:

staticvoidprocessCommonDefinitionAnnotations(AnnotatedBeanDefinitionabd,AnnotatedTypeMetadatametadata){

AnnotationAttributeslazy=attributesFor(metadata,Lazy.class);

if(lazy!=null){

abd.setLazyInit(lazy.getBoolean("value"));

elseif(abd.getMetadata()!=metadata){

lazy=attributesFor(abd.getMetadata(),Lazy.class);

if(lazy!=null){

abd.setLazyInit(lazy.getBoolean("value"));

if(metadata.isAnnotated(Primary.class.getName())){

abd.setPrimary(true);

AnnotationAttributesdependsOn=attributesFor(metadata,DependsOn.class);

if(dependsOn!=null){

abd.setDependsOn(dependsOn.getStringArray("value"));

AnnotationAttributesrole=attributesFor(metadata,Role.class);

if(role!=null){

abd.setRole(role.getNumber("value").intValue());

AnnotationAttributesdescription=attributesFor(metadata,Description.class);

if(description!=null){

abd.setDescription(description.getString("value"));

checkCandidate

這一步主要是檢查是否我們的bean定義map注冊(cè)中已經(jīng)存在了,不過我們工作中基本上都會(huì)通過,如果存在多個(gè)那會(huì)拋異常:

protectedbooleancheckCandidate(StringbeanName,BeanDefinitionbeanDefinition)throwsIllegalStateException{

if(!this.registry.containsBeanDefinition(beanName)){

returntrue;

BeanDefinitionexistingDef=this.registry.getBeanDefinition(beanName);

BeanDefinitionoriginatingDef=existingDef.getOriginatingBeanDefinition();

if(originatingDef!=null){

existingDef=originatingDef;

//是否兼容,如果兼容返回false表示不會(huì)重新注冊(cè)到Spring容器中,如果不沖突則會(huì)拋異常。

if(isCompatible(beanDefinition,existingDef)){

returnfalse;

thrownewConflictingBeanDefinitionException("Annotation-specifiedbeanname'"+beanName+

"'forbeanclass["+beanDefinition.getBeanClassName()+"]conflictswithexisting,"+

"non-compatiblebeandefinitionofsamenameandclass["+existingDef.getBeanClassName()+"]");

可是你像我這樣下面寫的話就不會(huì)出現(xiàn)異常,但是工作中肯定也不會(huì)這么用,這里只做展示,AppConfig和AppConfig1都是對(duì)同樣的配置,會(huì)對(duì)同一個(gè)包路徑掃描兩次:

AnnotationConfigApplicationContextapplicationContext=newAnnotationConfigApplicationContext();

applicationContext.register(AppConfig.class);

applicationContext.register(AppConfig1.class);

applicationContext.refresh();

UserServicebean=applicationContext.getBean(UserService.class);

bean.test();

registerBeanDefinition

那么最后當(dāng)前的bean定義正式生成,并注冊(cè)到我們之前經(jīng)常說的DefaultListableBeanFactory的MapString,BeanDefinitionbeanDefinitionMap屬性。

publicstaticvoidregisterBeanDefinition(

BeanDefinitionHolderdefinitionHolder,BeanDefinitionRegistryregistry)

throwsBeanDefinitionStoreException{

//Registerbeandefinitionunderprimaryname.

StringbeanName=definitionHolder.getBeanName();

registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());

//Registeraliasesforbeanname,ifany.

String[]aliases=definitionHolder.getAliases();

if(aliases!=null){

for(Stringalias:aliases){

registry.registerAlias(beanName,alias);

合并bean定義

這個(gè)是非常重要的一個(gè)步驟,所以單獨(dú)拿出來說下,這個(gè)步驟也是獲取bean之前的最后一個(gè)對(duì)bean定義做修改的地方,getMergedLocalBeanDefinition(beanName);通過beanname來獲取合并后的bean定義,這是什么意思呢?看下源碼:

protectedRootBeanDefinitiongetMergedBeanDefinition(

StringbeanName,BeanDefinitionbd,@NullableBeanDefinitioncontainingBd)

throwsBeanDefinitionStoreException{

synchronized(this.mergedBeanDefinitions){

RootBeanDefinitionmbd=null;

RootBeanDefinitionprevious=null;

//Checkwithfulllocknowinordertoenforcethesamemergedinstance.

if(containingBd==null){

mbd=this.mergedBeanDefinitions.get(beanName);

if(mbd==null||mbd.stale){

previous=mbd;

if(bd.getParentName()==null){

//Usecopyofgivenrootbeandefinition.

if(bdinstanceofRootBeanDefinition){

mbd=((RootBeanDefinition)bd).cloneBeanDefinition();

else{

mbd=newRootBeanDefinition(bd);

else{

//Childbeandefinition:needstobemergedwithparent.

//pbd表示parentBeanDefinition

BeanDefinitionpbd;

try{

StringparentBeanName=transformedBeanName(bd.getParentName());

if(!beanName.equals(parentBeanName)){

pbd=getMergedBeanDefinition(parentBeanName);

else{

BeanFactoryparent=getParentBeanFactory();

if(parentinstanceofConfigurableBeanFactory){

pbd=((ConfigurableBeanFactory)parent).getMergedBeanDefinition(parentBeanName);

else{

......

catch(NoSuchBeanDefinitionExceptionex){

......

//Deepcopywithoverriddenvalues.

//子BeanDefinition的屬性覆蓋父BeanDefinition的屬性,這就是合并

mbd=newRootBeanDefinition(pbd);

mbd.overrideFrom(bd);

//Setdefaultsingletonscope,ifnotconfiguredbefore.

if(!StringUtils.hasLength(mbd.getScope())){

mbd.setScope(SCOPE_SINGLETON);

if

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論