Spring Bean的生命周期是Spring面試熱點問題。這個問題即考察對Spring的微觀了解疮茄,又考察對Spring的宏觀認識伦吠,想要答好并不容易!本文希望能夠從源碼角度入手惹骂,幫助面試者徹底搞定Spring Bean的生命周期苏携。
只有四個!
是的对粪,Spring Bean的生命周期只有這四個階段右冻。把這四個階段和每個階段對應的擴展點糅合在一起雖然沒有問題,但是這樣非常凌亂著拭,難以記憶国旷。要徹底搞清楚Spring的生命周期,首先要把這四個階段牢牢記住茫死。實例化和屬性賦值對應構造方法和setter方法的注入跪但,初始化和銷毀是用戶能自定義擴展的兩個階段。在這四步之間穿插的各種擴展點峦萎,稍后會講屡久。
????1.實例化 Instantiation
????2.屬性賦值 Populate
????3.初始化 Initialization
????4.銷毀 Destruction
實例化 -> 屬性賦值 -> 初始化 -> 銷毀
主要邏輯都在doCreate()方法中,邏輯很清晰爱榔,就是順序調用以下三個方法被环,這三個方法與三個生命周期階段一一對應,非常重要详幽,在后續(xù)擴展接口分析中也會涉及筛欢。
1.createBeanInstance() -> 實例化
2.populateBean() -> 屬性賦值
3.initializeBean() -> 初始化
源碼如下浸锨,能證明實例化,屬性賦值和初始化這三個生命周期的存在版姑。關于本文的Spring源碼都將忽略無關部分柱搜,便于理解:
//?忽略了無關代碼
protected?Object?doCreateBean(final?String?beanName,?final?RootBeanDefinition?mbd,?final?@Nullable?Object[]?args)
??????throws?BeanCreationException?{
???//?Instantiate?the?bean.
???BeanWrapper?instanceWrapper?=?null;
???if?(instanceWrapper?==?null)?{
???????//?實例化階段!
??????instanceWrapper?=?createBeanInstance(beanName,?mbd,?args);
???}
???//?Initialize?the?bean?instance.
???Object?exposedObject?=?bean;
???try?{
???????//?屬性賦值階段剥险!
??????populateBean(beanName,?mbd,?instanceWrapper);
???????//?初始化階段聪蘸!
??????exposedObject?=?initializeBean(beanName,?exposedObject,?mbd);
???}
???}
至于銷毀,是在容器關閉時調用的表制,詳見ConfigurableApplicationContext#close()
常用擴展點
Spring生命周期相關的常用擴展點非常多健爬,所以問題不是不知道,而是記不住或者記不牢么介。其實記不住的根本原因還是不夠了解娜遵,這里通過源碼+分類的方式幫大家記憶。
第一大類:影響多個Bean的接口
實現了這些接口的Bean會切入到多個Bean的生命周期中壤短。正因為如此设拟,這些接口的功能非常強大,Spring內部擴展也經常使用這些接口鸽扁,例如自動注入以及AOP的實現都和他們有關。
? ? 1.BeanPostProcessor
? ? 2.InstantiationAwareBeanPostProcessor
這兩兄弟可能是Spring擴展中最重要的兩個接口镶骗!InstantiationAwareBeanPostProcessor作用于實例化階段的前后桶现,BeanPostProcessor作用于初始化階段的前后。正好和第一鼎姊、第三個生命周期階段對應骡和。通過圖能更好理解:
InstantiationAwareBeanPostProcessor實際上繼承了BeanPostProcessor接口,嚴格意義上來看他們不是兩兄弟相寇,而是兩父子。但是從生命周期角度我們重點關注其特有的對實例化階段的影響,圖中省略了從BeanPostProcessor繼承的方法裤园。
InstantiationAwareBeanPostProcessor?extends?BeanPostProcessor
InstantiationAwareBeanPostProcessor源碼分析:
@Override
????protected?Object?createBean(String?beanName,?RootBeanDefinition?mbd,?@Nullable?Object[]?args)
????????????throws?BeanCreationException?{
????????try?{
????????????//?Give?BeanPostProcessors?a?chance?to?return?a?proxy?instead?of?the?target?bean?instance.
????????????//?postProcessBeforeInstantiation方法調用點铐殃,這里就不跟進了,
????????????//?有興趣的同學可以自己看下佳励,就是for循環(huán)調用所有的InstantiationAwareBeanPostProcessor
????????????Object?bean?=?resolveBeforeInstantiation(beanName,?mbdToUse);
????????????if?(bean?!=?null)?{
????????????????return?bean;
????????????}
????????}
????????try?{???
????????????//?上文提到的doCreateBean方法休里,可以看到
????????????//?postProcessBeforeInstantiation方法在創(chuàng)建Bean之前調用
????????????Object?beanInstance?=?doCreateBean(beanName,?mbdToUse,?args);
????????????if?(logger.isTraceEnabled())?{
????????????????logger.trace("Finished?creating?instance?of?bean?'"?+?beanName?+?"'");
????????????}
????????????return?beanInstance;
????????}
????}
可以看到,postProcessBeforeInstantiation在doCreateBean之前調用赃承,也就是在bean實例化之前調用的妙黍,英文源碼注釋解釋道該方法的返回值會替換原本的Bean作為代理,這也是Aop等功能實現的關鍵點瞧剖。
postProcessAfterInstantiation調用點拭嫁,忽略無關代碼:
protected void populateBean(String?beanName,?RootBeanDefinition?mbd,?
@Nullable?BeanWrapper?bw){
???//?Give?any?InstantiationAwareBeanPostProcessors?the?opportunity?to?modify?the
???//?state?of?the?bean?before?properties?are?set.?This?can?be?used,?for?example,
???//?to?support?styles?of?field?injection.
???boolean?continueWithPropertyPopulation?=?true;
????//?InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
????//?方法作為屬性賦值的前置檢查條件可免,在屬性賦值之前執(zhí)行,能夠影響是否進行屬性賦值做粤!
???if?(!mbd.isSynthetic()?&&?hasInstantiationAwareBeanPostProcessors())?{
??????for?(BeanPostProcessor?bp?:?getBeanPostProcessors())?{
?????????if?(bp?instanceof?InstantiationAwareBeanPostProcessor)?{
????????????InstantiationAwareBeanPostProcessor?ibp?=?(InstantiationAwareBeanPostProcessor)?bp;
????????????if?(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(),?beanName))?{
???????????????continueWithPropertyPopulation?=?false;
???????????????break;
????????????}
?????????}
??????}
???}
???//?忽略后續(xù)的屬性賦值操作代碼
}
可以看到該方法在屬性賦值方法內浇借,但是在真正執(zhí)行賦值操作之前。其返回值為boolean驮宴,返回false時可以阻斷屬性賦值階段(continueWithPropertyPopulation = false;)逮刨。
關于BeanPostProcessor執(zhí)行階段的源碼穿插在下文Aware接口的調用時機分析中,因為部分Aware功能的就是通過他實現的!只需要先記住BeanPostProcessor在初始化前后調用就可以了堵泽。
第二大類:只調用一次的接口
這一大類接口的特點是功能豐富修己,常用于用戶自定義擴展。
第二大類中又可以分為兩類:
? ? 1.Aware類型的接口
? ? 2.生命周期接口
無所不知的Aware
Aware類型的接口的作用就是讓我們能夠拿到Spring容器中的一些資源迎罗〔欠撸基本都能夠見名知意,Aware之前的名字就是可以拿到什么資源纹安,例如BeanNameAware可以拿到BeanName尤辱,以此類推。調用時機需要注意:所有的Aware方法都是在初始化階段之前調用的厢岂!
Aware接口眾多光督,這里同樣通過分類的方式幫助大家記憶。
Aware接口具體可以分為兩組塔粒,至于為什么這么分结借,詳見下面的源碼分析。如下排列順序同樣也是Aware接口的執(zhí)行順序卒茬,能夠見名知意的接口不再解釋船老。
Aware Group1
? ? 1.BeanNameAware
? ? 2.BeanClassLoaderAware
? ? 3.BeanFactoryAware
Aware Group2
? ? 1.EnvironmentAware
? ? 2.EmbeddedValueResolverAware 這個知道的人可能不多,實現該接口能夠獲取Spring EL解析器圃酵,用戶的自定義注解需要支持spel表達式的時候可以使用柳畔,非常方便。
? ? ????3.????ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 這幾個接口可能讓人有點懵郭赐,實際上這幾個接口可以一起記薪韩,其返回值實質上都是當前的ApplicationContext對象,因為ApplicationContext是一個復合接口捌锭,如下:
public?interface ApplicationContextextendsEnvironmentCapable,ListableBeanFactory,HierarchicalBeanFactory,
MessageSource,ApplicationEventPublisher,ResourcePatternResolver?{}
這里涉及到另一道面試題躬存,ApplicationContext和BeanFactory的區(qū)別,可以從ApplicationContext繼承的這幾個接口入手舀锨,除去BeanFactory相關的兩個接口就是ApplicationContext獨有的功能岭洲,這里不詳細說明。
Aware調用時機源碼分析
詳情如下坎匿,忽略了部分無關代碼盾剩。代碼位置就是我們上文提到的initializeBean方法詳情雷激,這也說明了Aware都是在初始化階段之前調用的!
//?見名知意告私,初始化階段調用的方法
????protected?Object?initializeBean(final?String?beanName,?final?Object?bean,?@Nullable?RootBeanDefinition?mbd)?{
????????//?這里調用的是Group1中的三個Bean開頭的Aware
????????invokeAwareMethods(beanName,?bean);
????????Object?wrappedBean?=?bean;
????????//?這里調用的是Group2中的幾個Aware屎暇,
????????//?而實質上這里就是前面所說的BeanPostProcessor的調用點!
????????//?也就是說與Group1中的Aware不同驻粟,這里是通過BeanPostProcessor(ApplicationContextAwareProcessor)實現的根悼。
????????wrappedBean?=?applyBeanPostProcessorsBeforeInitialization(wrappedBean,?beanName);
????????//?下文即將介紹的InitializingBean調用點
????????invokeInitMethods(beanName,?wrappedBean,?mbd);
????????//?BeanPostProcessor的另一個調用點
????????wrappedBean?=?applyBeanPostProcessorsAfterInitialization(wrappedBean,?beanName);
????????return?wrappedBean;
????}
可以看到并不是所有的Aware接口都使用同樣的方式調用。Bean××Aware都是在代碼中直接調用的蜀撑,而ApplicationContext相關的Aware都是通過BeanPostProcessor#postProcessBeforeInitialization()實現的挤巡。
感興趣的可以自己看一下ApplicationContextAwareProcessor這個類的源碼,就是判斷當前創(chuàng)建的Bean是否實現了相關的Aware方法酷麦,如果實現了會調用回調方法將資源傳遞給Bean矿卑。
至于Spring為什么這么實現,應該沒什么特殊的考量沃饶。也許和Spring的版本升級有關母廷。基于對修改關閉糊肤,對擴展開放的原則琴昆,Spring對一些新的Aware采用了擴展的方式添加。
BeanPostProcessor的調用時機也能在這里體現馆揉,包圍住invokeInitMethods方法业舍,也就說明了在初始化階段的前后執(zhí)行。
關于Aware接口的執(zhí)行順序把介,其實只需要記住第一組在第二組執(zhí)行之前就行了勤讽。每組中各個Aware方法的調用順序其實沒有必要記蟋座,有需要的時候點進源碼一看便知拗踢。
簡單的兩個生命周期接口
至于剩下的兩個生命周期接口就很簡單了,實例化和屬性賦值都是Spring幫助我們做的向臀,能夠自己實現的有初始化和銷毀兩個生命周期階段巢墅。
InitializingBean 對應生命周期的初始化階段,在上面源碼的invokeInitMethods(beanName, wrappedBean, mbd);方法中調用券膀。
有一點需要注意君纫,因為Aware方法都是執(zhí)行在初始化方法之前,所以可以在初始化方法中放心大膽的使用Aware接口獲取的資源芹彬,這也是我們自定義擴展Spring的常用方式蓄髓。
除了實現InitializingBean接口之外還能通過注解或者xml配置的方式指定初始化方法,至于這幾種定義方式的調用順序其實沒有必要記舒帮。因為這幾個方法對應的都是同一個生命周期会喝,只是實現方式不同陡叠,我們一般只采用其中一種方式。
DisposableBean 類似于InitializingBean肢执,對應生命周期的銷毀階段枉阵,以ConfigurableApplicationContext#close()方法作為入口,實現是通過循環(huán)取所有實現了DisposableBean接口的Bean然后調用其destroy()方法 预茄。感興趣的可以自行跟一下源碼兴溜。
擴展閱讀: BeanPostProcessor 注冊時機與執(zhí)行順序
注冊時機
我們知道BeanPostProcessor也會注冊為Bean,那么Spring是如何保證BeanPostProcessor在我們的業(yè)務Bean之前初始化完成呢耻陕?
請看我們熟悉的refresh()方法的源碼拙徽,省略部分無關代碼:
@Override
????publicvoidrefresh()throwsBeansException,?IllegalStateException{
????????synchronized?(this.startupShutdownMonitor)?{
????????????try?{
????????????????//?Allows?post-processing?of?the?bean?factory?in?context?subclasses.
????????????????postProcessBeanFactory(beanFactory);
????????????????//?Invoke?factory?processors?registered?as?beans?in?the?context.
????????????????invokeBeanFactoryPostProcessors(beanFactory);
????????????????//?Register?bean?processors?that?intercept?bean?creation.
????????????????//?所有BeanPostProcesser初始化的調用點
????????????????registerBeanPostProcessors(beanFactory);
????????????????//?Initialize?message?source?for?this?context.
????????????????initMessageSource();
????????????????//?Initialize?event?multicaster?for?this?context.
????????????????initApplicationEventMulticaster();
????????????????//?Initialize?other?special?beans?in?specific?context?subclasses.
????????????????onRefresh();
????????????????//?Check?for?listener?beans?and?register?them.
????????????????registerListeners();
????????????????//?Instantiate?all?remaining?(non-lazy-init)?singletons.
????????????????//?所有單例非懶加載Bean的調用點
????????????????finishBeanFactoryInitialization(beanFactory);
????????????????//?Last?step:?publish?corresponding?event.
????????????????finishRefresh();
????????????}
????}
可以看出,Spring是先執(zhí)行registerBeanPostProcessors()進行BeanPostProcessors的注冊淮蜈,然后再執(zhí)行finishBeanFactoryInitialization初始化我們的單例非懶加載的Bean斋攀。
執(zhí)行順序
BeanPostProcessor有很多個,而且每個BeanPostProcessor都影響多個Bean梧田,其執(zhí)行順序至關重要淳蔼,必須能夠控制其執(zhí)行順序才行。關于執(zhí)行順序這里需要引入兩個排序相關的接口:PriorityOrdered裁眯、Ordered
PriorityOrdered是一等公民鹉梨,首先被執(zhí)行,PriorityOrdered公民之間通過接口返回值排序穿稳,Ordered是二等公民存皂,然后執(zhí)行,Ordered公民之間通過接口返回值排序
都沒有實現是三等公民逢艘,最后執(zhí)行旦袋。
在以下源碼中,可以很清晰的看到Spring注冊各種類型BeanPostProcessor的邏輯它改,根據實現不同排序接口進行分組疤孕。優(yōu)先級高的先加入,優(yōu)先級低的后加入央拖。
//?First,?invoke?the?BeanDefinitionRegistryPostProcessors?that?implement?PriorityOrdered.
//?首先祭阀,加入實現了PriorityOrdered接口的BeanPostProcessors,順便根據PriorityOrdered排了序
????????????String[]?postProcessorNames?=
????????????????????beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,?true,?false);
????????????for?(String?ppName?:?postProcessorNames)?{
????????????????if?(beanFactory.isTypeMatch(ppName,?PriorityOrdered.class))?{
????????????????????currentRegistryProcessors.add(beanFactory.getBean(ppName,?BeanDefinitionRegistryPostProcessor.class));
????????????????????processedBeans.add(ppName);
????????????????}
????????????}
????????????sortPostProcessors(currentRegistryProcessors,?beanFactory);
????????????registryProcessors.addAll(currentRegistryProcessors);
????????????invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,?registry);
????????????currentRegistryProcessors.clear();
????????????//?Next,?invoke?the?BeanDefinitionRegistryPostProcessors?that?implement?Ordered.
//?然后鲜戒,加入實現了Ordered接口的BeanPostProcessors专控,順便根據Ordered排了序
????????????postProcessorNames?=?beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,?true,?false);
????????????for?(String?ppName?:?postProcessorNames)?{
????????????????if?(!processedBeans.contains(ppName)?&&?beanFactory.isTypeMatch(ppName,?Ordered.class))?{
????????????????????currentRegistryProcessors.add(beanFactory.getBean(ppName,?BeanDefinitionRegistryPostProcessor.class));
????????????????????processedBeans.add(ppName);
????????????????}
????????????}
????????????sortPostProcessors(currentRegistryProcessors,?beanFactory);
????????????registryProcessors.addAll(currentRegistryProcessors);
????????????invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,?registry);
????????????currentRegistryProcessors.clear();
????????????//?Finally,?invoke?all?other?BeanDefinitionRegistryPostProcessors?until?no?further?ones?appear.
//?最后加入其他常規(guī)的BeanPostProcessors
????????????boolean?reiterate?=?true;
????????????while?(reiterate)?{
????????????????reiterate?=?false;
????????????????postProcessorNames?=?beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,?true,?false);
????????????????for?(String?ppName?:?postProcessorNames)?{
????????????????????if?(!processedBeans.contains(ppName))?{
????????????????????????currentRegistryProcessors.add(beanFactory.getBean(ppName,?BeanDefinitionRegistryPostProcessor.class));
????????????????????????processedBeans.add(ppName);
????????????????????????reiterate?=?true;
????????????????????}
????????????????}
????????????????sortPostProcessors(currentRegistryProcessors,?beanFactory);
????????????????registryProcessors.addAll(currentRegistryProcessors);
????????????????invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,?registry);
????????????????currentRegistryProcessors.clear();
????????????}
根據排序接口返回值排序,默認升序排序遏餐,返回值越低優(yōu)先級越高伦腐。
????/**
?????*?Useful?constant?for?the?highest?precedence?value.
?????*?@see?java.lang.Integer#MIN_VALUE
?????*/
????int?HIGHEST_PRECEDENCE?=?Integer.MIN_VALUE;
????/**
?????*?Useful?constant?for?the?lowest?precedence?value.
?????*?@see?java.lang.Integer#MAX_VALUE
?????*/
????int?LOWEST_PRECEDENCE?=?Integer.MAX_VALUE;
PriorityOrdered、Ordered接口作為Spring整個框架通用的排序接口失都,在Spring中應用廣泛柏蘑,也是非常重要的接口颖系。
總結
Spring Bean的生命周期分為四個階段和多個擴展點。擴展點又可以分為影響多個Bean和影響單個Bean辩越。整理如下:
四個階段
實例化 Instantiation
屬性賦值 Populate
初始化 Initialization
銷毀 Destruction
多個擴展點
影響多個Bean
BeanPostProcessor
InstantiationAwareBeanPostProcessor
影響單個Bean
Aware
Aware Group1
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group2
EnvironmentAware
EmbeddedValueResolverAware
ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
生命周期
InitializingBean
DisposableBean
至此嘁扼,Spring Bean的生命周期介紹完畢,由于作者水平有限難免有疏漏黔攒,歡迎留言糾錯趁啸。