版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年大學(xué)大三(工商管理)財(cái)務(wù)管理基礎(chǔ)理論測(cè)試題及答案
- 2026年智能停車輔助系統(tǒng)項(xiàng)目公司成立分析報(bào)告
- 2025年中職水利水電工程施工(水工建筑物基礎(chǔ))試題及答案
- 2026年家政服務(wù)教學(xué)(家政服務(wù)應(yīng)用)試題及答案
- 2025年高職防災(zāi)減災(zāi)技術(shù)(災(zāi)害預(yù)防措施)試題及答案
- 2025年高職物理學(xué)(相對(duì)論)試題及答案
- 2025年中職作曲與作曲技術(shù)理論(作曲理論)試題及答案
- 2025年中職(茶葉生產(chǎn)與加工)茶葉采摘標(biāo)準(zhǔn)試題及答案
- 2025年大學(xué)大四(印刷企業(yè)管理)企業(yè)運(yùn)營(yíng)專項(xiàng)測(cè)試題及答案
- 2025年大學(xué)生態(tài)環(huán)境保護(hù)(生態(tài)修復(fù)工程)試題及答案
- 《裝飾裝修工程》課件
- 2025年浙江杭州市水務(wù)集團(tuán)有限公司招聘筆試參考題庫含答案解析
- 醫(yī)學(xué)倫理與倫理倫理
- 《醫(yī)療機(jī)構(gòu)胰島素安全使用管理規(guī)范》
- 2024-2025學(xué)年滬科版九年級(jí)(上)物理寒假作業(yè)(四)
- 華師福建 八下 數(shù)學(xué) 第18章 平行四邊形《平行四邊形的判定 第1課時(shí) 用邊的關(guān)系判定平行四邊形》課件
- 經(jīng)典版雨污分流改造工程施工組織設(shè)計(jì)方案
- 特殊作業(yè)安全管理監(jiān)護(hù)人專項(xiàng)培訓(xùn)課件
- 2024年天津駕駛員客運(yùn)從業(yè)資格證考試題及答案
- 電梯日管控、周排查、月調(diào)度內(nèi)容表格
- TCASME 1598-2024 家族辦公室架構(gòu)師職業(yè)技能等級(jí)
評(píng)論
0/150
提交評(píng)論