Spring 后置處理器源碼

在《幾種自定義Spring生命周期的初始化和銷毀方法》最后一段描述了啟動 Spring 容器過程中抗碰,初始化和銷毀方法的執(zhí)行時機掌腰,那么在 Spring 中是如何做到的呢是整?

注冊主配置類

Spring 使用AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class);指定主配置類砍的,將其注冊到 BeanFactory筏餐。除了主配置類葱椭,還會將一些基礎(chǔ)的后置處理器類注冊到 BeanFactory捂寿,如下所示:

  1. 初始化AnnotatedBeanDefinitionReader,內(nèi)部后置處理器注冊到BeanFactory
  • internalConfigurationAnnotationProcessor->ConfigurationClassPostProcessor
  • internalAutowiredAnnotationProcessor->AutowiredAnnotationBeanPostProcessor
  • internalCommonAnnotationProcessor->CommonAnnotationBeanPostProcessor
  • internalPersistenceAnnotationProcessor->PersistenceAnnotationBeanPostProcessor
  • internalEventListenerProcessor->EventListenerMethodProcessor
  • internalEventListenerFactory->DefaultEventListenerFactory
  1. 初始化ClassPathBeanDefinitionScanner挫以,加載環(huán)境和資源配置
  • Environment
  • ResourceLoader
注冊基礎(chǔ)BeanFactory

refresh()

Spring 中非常核心的源碼 AbstractApplicationContext.refresh()者蠕,顧名思義,這是用來更新 Spring 應(yīng)用上下文的方法掐松,對 Spring 容器進行初始化踱侣、更新等操作。

// 部分源碼
public void refresh() {
    // 取出注冊的 BeanFactory
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // 配置 BeanFactory
    prepareBeanFactory(beanFactory);
    // 初始化執(zhí)行 BeanFactory 后置處理器
    invokeBeanFactoryPostProcessors(beanFactory);
    // 注冊 Bean 后置處理器
    registerBeanPostProcessors(beanFactory);
    // 執(zhí)行 Bean 后置處理器
    finishBeanFactoryInitialization(beanFactory);
}

1大磺、初始化執(zhí)行 BeanFactory 后置處理器

整體順序


首先會按照順序執(zhí)行 BeanDefinitionRegistryPostProcessor 的實現(xiàn)類

  1. 執(zhí)行實現(xiàn)了 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor抡句。
  2. 執(zhí)行實現(xiàn)了 Ordered 的 BeanDefinitionRegistryPostProcessor。
  3. 執(zhí)行所有剩下的 BeanDefinitionRegistryPostProcessor杠愧。

上面的每一步都會先在容器中==初始化 Bean==待榔,然后去執(zhí)行 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry() 方法。因為 BeanDefinitionRegistryPostProcessor 繼承了 BeanFactoryPostProcessor流济,所以也會執(zhí)行 postProcessBeanFactory() 方法锐锣。


然后按順序執(zhí)行 BeanFactoryPostProcessor 的實現(xiàn)類

  1. 執(zhí)行實現(xiàn)了 PriorityOrdered 的 BeanFactoryPostProcessor。
  2. 執(zhí)行實現(xiàn)了 Ordered 的 BeanFactoryPostProcessor绳瘟。
  3. 執(zhí)行所有剩下的 BeanFactoryPostProcessor雕憔。

上面的每一步都會先在容器中==初始化 Bean==,然后去執(zhí)行 BeanFactoryPostProcessor 的 postProcessBeanFactory() 方法糖声。


執(zhí)行細節(jié)

以 ConfigurationClassPostProcessor 為例斤彼,這個類是 BeanDefinitionRegistryPostProcessor 的實現(xiàn)類,是 @Configuration 注解配置類的啟動引導類蘸泻,在注冊主配置類時琉苇,已經(jīng)注冊到 BeanFactory,此外悦施,此類還實現(xiàn)了 PriorityOrdered并扇,從執(zhí)行順序可知,它會被優(yōu)先執(zhí)行抡诞。

1拜马、ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()

  1. 首先會找到主配置類,即標注 @Configuration 的類沐绒。
  2. 創(chuàng)建配置類解析器 ConfigurationClassParser 俩莽,以主配置類為入口,其方法 doProcessConfigurationClass() 會根據(jù)主配置類上標注的注解乔遮,按照下面的順序依次找到所有的 Spring 組件扮超。
    • @PropertySource 將配置數(shù)據(jù)加載到緩存
    • @ComponentScan 掃描類路徑下的所有類,過濾出 @Component 注解類
    • @Import 加載 @Import 導入的類。如果該類是 ImportSelector出刷,則會去執(zhí)行其方法 selectImports()璧疗;如果是 ImportBeanDefinitionRegistrar,則只是將其加入緩存馁龟,還不會執(zhí)行他的方法崩侠;否則,直接當作 @Configuration 注解類處理坷檩。
    • @ImportResource
    • @Bean 加載 @Bean 標注的方法却音。
    • 接口默認方法
    • 父類
  3. ConfigurationClassBeanDefinitionReader 遍歷找到的所有組件,并將 @Import 導入的類注冊到 BeanFactory矢炼。此時系瓢,會執(zhí)行 ImportBeanDefinitionRegistrar.registerBeanDefinitions() 方法

2、ConfigurationClassPostProcessor.postProcessBeanFactory()

  1. 執(zhí)行 BeanDefinitionRegistryPostProcessor 實現(xiàn)類的 postProcessBeanFactory()句灌,利用CGLib增強配置類
  2. 注冊后置處理器 ImportAwareBeanPostProcessor

3夷陋、ImportAwareBeanPostProcessor.postProcessBeanFactory()

  1. 回調(diào)ImportAware.setImportMetadata()

執(zhí)行剩下的 BeanFactoryPostProcessor 實現(xiàn)類的 postProcessBeanFactory()


至此,BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 都已經(jīng)執(zhí)行完了胰锌, 但是一部分自定義的 Bean 還沒開始初始化骗绕,需要執(zhí)行 Bean 后置處理器。

invokeBeanFactoryPostProcessors

2资昧、執(zhí)行 Bean 后置處理器

這個方法會將所有單例酬土、非懶加載對象進行實例化。

主要流程:

  1. ==初始化 Bean==
  2. 回調(diào)SmartInitializingSingleton.afterSingletonsInstantiated()

至此榛搔,容器中的 Bean 都已經(jīng)創(chuàng)建好了诺凡,再來看下上面標黃的==初始化 Bean==的流程东揣,《幾種自定義Spring生命周期的初始化和銷毀方法》中描述的一些過程都是在這個里面執(zhí)行的践惑。

finishBeanFactoryInitialization

3、==初始化 Bean==

AbstractBeanFactory 是 BeanFactory 的抽象實現(xiàn)類嘶卧,創(chuàng)建 Bean 的入口是 doGetBean()尔觉。首先,它會檢查緩存中是否存在該 Bean芥吟,如果存在侦铜,則直接獲取,并返回钟鸵;如果緩存中不存在钉稍,再看是創(chuàng)建 Bean 的流程。

AbstractAutowireCapableBeanFactory 實現(xiàn)了 AbstractBeanFactory 創(chuàng)建 Bean 的方法 createBean()棺耍,Spring 會調(diào)用它的方法 doCreateBean() 來創(chuàng)建 Bean 實例贡未。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

    // 1.反射執(zhí)行構(gòu)造器方法
    BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
    
    // 屬性賦值
    populateBean(beanName, mbd, instanceWrapper);
    // 初始化 Bean
    exposedObject = initializeBean(beanName, exposedObject, mbd);->4.afterPropertiesSet->5.invokeCustomInitMethod

    return exposedObject;
}

上述源碼中 initializeBean() 方法中會順序執(zhí)行

  • BeanPostProcessor.postProcessBeforeInitialization()
  • @PostConstruct
  • InitializingBean.afterPropertiesSet()
  • initMethod()
  • BeanPostProcessor.postProcessAfterInitialization()

主要源碼和注釋如下

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // 執(zhí)行 Aware 接口實現(xiàn)方法
    invokeAwareMethods(beanName, bean);

    // 2.執(zhí)行 BeanPostProcessor.postProcessBeforeInitialization()
    // 3.上面的方法內(nèi)部實際上回去執(zhí)行 @PostConstruct 注解的方法
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

    // 4.執(zhí)行 InitializingBean.afterPropertiesSet()
    // 5.然后執(zhí)行自定義的 initMethod() 方法
    invokeInitMethods(beanName, wrappedBean, mbd);
    
    // 6.執(zhí)行 BeanPostProcessor.postProcessAfterInitialization()
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    return wrappedBean;
}

注意,initializeBean() 方法中的 invokeAwareMethods() 會去執(zhí)行部分 Aware 接口實現(xiàn)類的方法,見 Spring Aware源碼俊卤。

初始化 Bean

總結(jié)

  • Spring 啟動時嫩挤,首先會將主配置類和基礎(chǔ)的后置處理器類注冊到 BeanFactory
  • 調(diào)用 refresh() 方法,將上述 BeanFactory 中的后置處理器取出消恍,并執(zhí)行后置處理器的實現(xiàn)方法岂昭,掃描所有可用的 Bean 注冊到 BeanFactory
  • 將 BeanFactory 中所有可用的 Bean 進行最終的初始化工作
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狠怨,隨后出現(xiàn)的幾起案子约啊,更是在濱河造成了極大的恐慌,老刑警劉巖取董,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棍苹,死亡現(xiàn)場離奇詭異,居然都是意外死亡茵汰,警方通過查閱死者的電腦和手機枢里,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹂午,“玉大人栏豺,你說我怎么就攤上這事《剐兀” “怎么了奥洼?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長晚胡。 經(jīng)常有香客問我灵奖,道長,這世上最難降的妖魔是什么估盘? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任瓷患,我火速辦了婚禮,結(jié)果婚禮上遣妥,老公的妹妹穿的比我還像新娘擅编。我一直安慰自己,他們只是感情好箫踩,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布爱态。 她就那樣靜靜地躺著,像睡著了一般境钟。 火紅的嫁衣襯著肌膚如雪锦担。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天慨削,我揣著相機與錄音洞渔,去河邊找鬼鱼的。 笑死,一個胖子當著我的面吹牛痘煤,可吹牛的內(nèi)容都是我干的凑阶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼衷快,長吁一口氣:“原來是場噩夢啊……” “哼宙橱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蘸拔,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤师郑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后调窍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宝冕,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年邓萨,在試婚紗的時候發(fā)現(xiàn)自己被綠了地梨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡缔恳,死狀恐怖宝剖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歉甚,我是刑警寧澤万细,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站纸泄,受9級特大地震影響赖钞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜聘裁,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一雪营、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咧虎,春花似錦卓缰、人聲如沸计呈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捌显。三九已至茁彭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扶歪,已是汗流浹背理肺。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工摄闸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妹萨。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓年枕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親乎完。 傳聞我的和親對象是個殘疾皇子熏兄,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容