<meta charset="utf-8">
Spring Bean的生命周期是Spring面試熱點問題陆淀。這個問題即考察對Spring的微觀了解,又考察對Spring的宏觀認識,想要答好并不容易厢岂!本文希望能夠從源碼角度入手光督,幫助面試者徹底搞定Spring Bean的生命周期。
只有四個塔粒!
是的结借,Spring Bean的生命周期只有這四個階段。把這四個階段和每個階段對應(yīng)的擴展點糅合在一起雖然沒有問題卒茬,但是這樣非常凌亂船老,難以記憶。要徹底搞清楚Spring的生命周期圃酵,首先要把這四個階段牢牢記住柳畔。實例化和屬性賦值對應(yīng)構(gòu)造方法和setter方法的注入,初始化和銷毀是用戶能自定義擴展的兩個階段郭赐。在這四步之間穿插的各種擴展點薪韩,稍后會講。
- 實例化 Instantiation
- 屬性賦值 Populate
- 初始化 Initialization
- 銷毀 Destruction
實例化 -> 屬性賦值 -> 初始化 -> 銷毀
主要邏輯都在doCreate()方法中堪置,邏輯很清晰躬存,就是順序調(diào)用以下三個方法,這三個方法與三個生命周期階段一一對應(yīng)舀锨,非常重要岭洲,在后續(xù)擴展接口分析中也會涉及。
- createBeanInstance() -> 實例化
- populateBean() -> 屬性賦值
- initializeBean() -> 初始化
源碼如下坎匿,能證明實例化盾剩,屬性賦值和初始化這三個生命周期的存在。關(guān)于本文的Spring源碼都將忽略無關(guān)部分替蔬,便于理解:
// 忽略了無關(guān)代碼
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);
}
}
至于銷毀驻粟,是在容器關(guān)閉時調(diào)用的,詳見ConfigurableApplicationContext#close()
常用擴展點
Spring生命周期相關(guān)的常用擴展點非常多凶异,所以問題不是不知道蜀撑,而是記不住或者記不牢。其實記不住的根本原因還是不夠了解剩彬,這里通過源碼+分類的方式幫大家記憶酷麦。
第一大類:影響多個Bean的接口
實現(xiàn)了這些接口的Bean會切入到多個Bean的生命周期中。正因為如此喉恋,這些接口的功能非常強大沃饶,Spring內(nèi)部擴展也經(jīng)常使用這些接口母廷,例如自動注入以及AOP的實現(xiàn)都和他們有關(guān)。
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
這兩兄弟可能是Spring擴展中最重要的兩個接口糊肤!InstantiationAwareBeanPostProcessor作用于實例化階段的前后琴昆,BeanPostProcessor作用于初始化階段的前后。正好和第一轩褐、第三個生命周期階段對應(yīng)椎咧。通過圖能更好理解:
InstantiationAwareBeanPostProcessor實際上繼承了BeanPostProcessor接口玖详,嚴格意義上來看他們不是兩兄弟把介,而是兩父子。但是從生命周期角度我們重點關(guān)注其特有的對實例化階段的影響蟋座,圖中省略了從BeanPostProcessor繼承的方法拗踢。
InstantiationAwareBeanPostProcessor extends BeanPostProcessor
InstantiationAwareBeanPostProcessor源碼分析:
- postProcessBeforeInstantiation調(diào)用點,忽略無關(guān)代碼:
@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方法調(diào)用點向臀,這里就不跟進了巢墅,
// 有興趣的同學(xué)可以自己看下,就是for循環(huán)調(diào)用所有的InstantiationAwareBeanPostProcessor
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
try {
// 上文提到的doCreateBean方法券膀,可以看到
// postProcessBeforeInstantiation方法在創(chuàng)建Bean之前調(diào)用
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}
可以看到君纫,postProcessBeforeInstantiation在doCreateBean之前調(diào)用,也就是在bean實例化之前調(diào)用的芹彬,英文源碼注釋解釋道該方法的返回值會替換原本的Bean作為代理蓄髓,這也是Aop等功能實現(xiàn)的關(guān)鍵點。
- postProcessAfterInstantiation調(diào)用點舒帮,忽略無關(guān)代碼:
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ù)的屬性賦值操作代碼
}
可以看到該方法在屬性賦值方法內(nèi)肢执,但是在真正執(zhí)行賦值操作之前。其返回值為boolean译红,返回false時可以阻斷屬性賦值階段(continueWithPropertyPopulation = false;
)预茄。
關(guān)于BeanPostProcessor執(zhí)行階段的源碼穿插在下文Aware接口的調(diào)用時機分析中,因為部分Aware功能的就是通過他實現(xiàn)的!只需要先記住BeanPostProcessor在初始化前后調(diào)用就可以了侦厚。
第二大類:只調(diào)用一次的接口
這一大類接口的特點是功能豐富耻陕,常用于用戶自定義擴展。
第二大類中又可以分為兩類:
- Aware類型的接口
- 生命周期接口
無所不知的Aware
Aware類型的接口的作用就是讓我們能夠拿到Spring容器中的一些資源假夺』打冢基本都能夠見名知意,Aware之前的名字就是可以拿到什么資源已卷,例如BeanNameAware
可以拿到BeanName梧田,以此類推。調(diào)用時機需要注意:所有的Aware方法都是在初始化階段之前調(diào)用的!
Aware接口眾多裁眯,這里同樣通過分類的方式幫助大家記憶鹉梨。
Aware接口具體可以分為兩組,至于為什么這么分穿稳,詳見下面的源碼分析存皂。如下排列順序同樣也是Aware接口的執(zhí)行順序,能夠見名知意的接口不再解釋逢艘。
Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware 這個知道的人可能不多旦袋,實現(xiàn)該接口能夠獲取Spring EL解析器,用戶的自定義注解需要支持spel表達式的時候可以使用它改,非常方便疤孕。
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 這幾個接口可能讓人有點懵,實際上這幾個接口可以一起記央拖,其返回值實質(zhì)上都是當前的ApplicationContext對象祭阀,因為ApplicationContext是一個復(fù)合接口,如下:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}
這里涉及到另一道面試題鲜戒,ApplicationContext和BeanFactory的區(qū)別专控,可以從ApplicationContext繼承的這幾個接口入手,除去BeanFactory相關(guān)的兩個接口就是ApplicationContext獨有的功能遏餐,這里不詳細說明伦腐。
Aware調(diào)用時機源碼分析
詳情如下,忽略了部分無關(guān)代碼境输。代碼位置就是我們上文提到的initializeBean方法詳情蔗牡,這也說明了Aware都是在初始化階段之前調(diào)用的!
// 見名知意嗅剖,初始化階段調(diào)用的方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 這里調(diào)用的是Group1中的三個Bean開頭的Aware
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
// 這里調(diào)用的是Group2中的幾個Aware辩越,
// 而實質(zhì)上這里就是前面所說的BeanPostProcessor的調(diào)用點!
// 也就是說與Group1中的Aware不同信粮,這里是通過BeanPostProcessor(ApplicationContextAwareProcessor)實現(xiàn)的黔攒。
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 下文即將介紹的InitializingBean調(diào)用點
invokeInitMethods(beanName, wrappedBean, mbd);
// BeanPostProcessor的另一個調(diào)用點
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
可以看到并不是所有的Aware接口都使用同樣的方式調(diào)用。Bean××Aware都是在代碼中直接調(diào)用的强缘,而ApplicationContext相關(guān)的Aware都是通過BeanPostProcessor#postProcessBeforeInitialization()實現(xiàn)的督惰。感興趣的可以自己看一下ApplicationContextAwareProcessor這個類的源碼,就是判斷當前創(chuàng)建的Bean是否實現(xiàn)了相關(guān)的Aware方法旅掂,如果實現(xiàn)了會調(diào)用回調(diào)方法將資源傳遞給Bean赏胚。
至于Spring為什么這么實現(xiàn),應(yīng)該沒什么特殊的考量商虐。也許和Spring的版本升級有關(guān)觉阅⊙掳蹋基于對修改關(guān)閉,對擴展開放的原則典勇,Spring對一些新的Aware采用了擴展的方式添加劫哼。
BeanPostProcessor的調(diào)用時機也能在這里體現(xiàn),包圍住invokeInitMethods方法割笙,也就說明了在初始化階段的前后執(zhí)行权烧。
關(guān)于Aware接口的執(zhí)行順序,其實只需要記住第一組在第二組執(zhí)行之前就行了伤溉。每組中各個Aware方法的調(diào)用順序其實沒有必要記般码,有需要的時候點進源碼一看便知。
簡單的兩個生命周期接口
至于剩下的兩個生命周期接口就很簡單了谈火,實例化和屬性賦值都是Spring幫助我們做的侈询,能夠自己實現(xiàn)的有初始化和銷毀兩個生命周期階段舌涨。
- InitializingBean 對應(yīng)生命周期的初始化階段糯耍,在上面源碼的
invokeInitMethods(beanName, wrappedBean, mbd);
方法中調(diào)用。
有一點需要注意囊嘉,因為Aware方法都是執(zhí)行在初始化方法之前温技,所以可以在初始化方法中放心大膽的使用Aware接口獲取的資源,這也是我們自定義擴展Spring的常用方式扭粱。
除了實現(xiàn)InitializingBean接口之外還能通過注解或者xml配置的方式指定初始化方法舵鳞,至于這幾種定義方式的調(diào)用順序其實沒有必要記。因為這幾個方法對應(yīng)的都是同一個生命周期琢蛤,只是實現(xiàn)方式不同蜓堕,我們一般只采用其中一種方式。 - DisposableBean 類似于InitializingBean博其,對應(yīng)生命周期的銷毀階段套才,以ConfigurableApplicationContext#close()方法作為入口,實現(xiàn)是通過循環(huán)取所有實現(xiàn)了DisposableBean接口的Bean然后調(diào)用其destroy()方法 慕淡。感興趣的可以自行跟一下源碼背伴。
擴展閱讀: BeanPostProcessor 注冊時機與執(zhí)行順序
注冊時機
我們知道BeanPostProcessor也會注冊為Bean,那么Spring是如何保證BeanPostProcessor在我們的業(yè)務(wù)Bean之前初始化完成呢峰髓?
請看我們熟悉的refresh()方法的源碼傻寂,省略部分無關(guān)代碼:
@Override
public void refresh() throws BeansException, 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初始化的調(diào)用點
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的調(diào)用點
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
可以看出,Spring是先執(zhí)行registerBeanPostProcessors()進行BeanPostProcessors的注冊携兵,然后再執(zhí)行finishBeanFactoryInitialization初始化我們的單例非懶加載的Bean疾掰。
執(zhí)行順序
BeanPostProcessor有很多個,而且每個BeanPostProcessor都影響多個Bean徐紧,其執(zhí)行順序至關(guān)重要静檬,必須能夠控制其執(zhí)行順序才行勒葱。關(guān)于執(zhí)行順序這里需要引入兩個排序相關(guān)的接口:PriorityOrdered、Ordered
PriorityOrdered是一等公民巴柿,首先被執(zhí)行凛虽,PriorityOrdered公民之間通過接口返回值排序
Ordered是二等公民,然后執(zhí)行广恢,Ordered公民之間通過接口返回值排序
都沒有實現(xiàn)是三等公民凯旋,最后執(zhí)行
在以下源碼中,可以很清晰的看到Spring注冊各種類型BeanPostProcessor的邏輯钉迷,根據(jù)實現(xiàn)不同排序接口進行分組至非。優(yōu)先級高的先加入,優(yōu)先級低的后加入糠聪。
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 首先荒椭,加入實現(xiàn)了PriorityOrdered接口的BeanPostProcessors,順便根據(jù)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.
// 然后舰蟆,加入實現(xiàn)了Ordered接口的BeanPostProcessors趣惠,順便根據(jù)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();
}
根據(jù)排序接口返回值排序,默認升序排序身害,返回值越低優(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中應(yīng)用廣泛侍瑟,也是非常重要的接口。
總結(jié)
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)
- Aware Group1
- 生命周期
- InitializingBean
- DisposableBean
- Aware
至此,Spring Bean的生命周期介紹完畢茧球,由于作者水平有限難免有疏漏庭瑰,歡迎留言糾錯。
作者:sunshujie1990
鏈接:http://www.reibang.com/p/1dec08d290c1
來源:簡書
著作權(quán)歸作者所有袜腥。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)见擦,非商業(yè)轉(zhuǎn)載請注明出處。