SpringBoot之Refresh流程的簡單說明
啟動入口
Springboot 程序的啟動入口是一個main方法,從這個入口方法一路追溯下去,最終可以找到Refresh方法的。
追溯流程如下:
org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String...) org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[]) org.springframework.boot.SpringApplication#run(java.lang.String...) org.springframework.boot.SpringApplication#refreshContext org.springframework.boot.SpringApplication#refresh(org.springframework.context.ConfigurableApplicationContext) org.springframework.context.ConfigurableApplicationContext#refresh
上面的幾個方法就是從main到refresh方法的路徑,中間省略了一兩個方法。用心找下就能追溯到refresh。
查看源碼的時候一定要抓住主路徑,放棄次要路徑,因為Spring框架臺復(fù)雜龐大了,不可能弄清楚所有的細(xì)節(jié)的。
Refresh方法
最終追溯到的refresh方法也是 ConfigurableApplicationContext
接口的方法, 這個接口有三個很重要的實現(xiàn)類, 我們先看下 AbstractApplicationContext
類中的refresh方法。
圖中是否有一種熟悉的感覺, 這個方法就是眾多的講Spring的博客文章都必定會說到的方法, 里面的每個步驟都是很重要的。
prepareBeanFactory
: 構(gòu)建上下文, 注冊各個框架的BeanPostProcesser和BeanFactoryPostProcessor的實現(xiàn)類。 注意是框架的。 還會設(shè)置忽略一些依賴比如各個Aware的依賴, 這個是為了注入其他的依賴的接口,所以不能用來注入依賴。 同時還會設(shè)置注冊依賴BeanFactory等的依賴。ObtainFreshBeanFactory
: 創(chuàng)建容器DefaultListableBeanFactory, 接著掃描classpath路徑下的所有的Bean信息,并生成對應(yīng)的BeanDefinition。prepareBeanfactory
: 一些框架依賴的beanFactoryPostProcessor在這里加載進(jìn)容器; 對于SPEL表達(dá)式在這里替換; 一些BeanPostProcessor在這里注入; Environment類的注入容器 ; BeanFactory也把自己放入容器中。postProcessBeanFactory
這個方法是個空實現(xiàn),但是web模塊中使用這個注入web的一些特有的ServletContextAwareProcessor實現(xiàn)類invokeBeanFactoryPostProcessors
方法,調(diào)用所有的BeanFactoryPostProcessors實現(xiàn)類的的postProcessBeanFactory方法; 會先調(diào)用可排序BeanFactoryPostProcessors實現(xiàn)類, 在調(diào)用沒有排序的postProcessBeanFactory實現(xiàn)類。 這里會先實例BeanFactoryPostProcessors的實現(xiàn)類,但是內(nèi)部的依賴還不會注入進(jìn)去, 所以在postProcessBeanFactory方法的邏輯中不要直接使用spring的依賴類。registerBeanPostProcessors
注冊BeanPostProcessor的實現(xiàn)類了。 這里會從容器中獲取所有的BeanPostProcessor的BeanDefinition , 并初始化后放(會注入依賴的)入到容器中。initMessageSource
初始化國際化的資源信息放入容器中initApplicationEventMulticaster
初始化spring的消息監(jiān)聽器。
這里會先檢查容器中用戶有沒有實現(xiàn)自己的事件監(jiān)聽器,如果有的話就使用用戶自定義的, 如果沒有就使用Spring自帶的簡單的事件監(jiān)聽器SimpleApplicationEventMulticaster。
這里監(jiān)聽器會 registerSingleton方法簡單的注冊到容器AbstractApplicationContext實現(xiàn) ApplicationEventPublisher接口(中間繼承間隔好幾層),而這個接口就有發(fā)布時間的方法。
所以一般的容器都有發(fā)布事件的能力。發(fā)布事件的邏輯是, publishEvent方法內(nèi)部調(diào)用SimpleApplicationEventMulticaster的* onApplicationEvent方法, 這個方法內(nèi)部會先從容器中獲取所有的事件監(jiān)聽器Bean,并放入緩存中。
然后在根據(jù)事件的類型選擇正確的事件處理器來處理, 這里會使用線程池來處理
onRefresh
這個方法 AbstractApplicationContext中是空實現(xiàn), 我們看下 ServletWebServerApplicationContext中的實現(xiàn)。 在這個子類中,這個方法被用來 初始化WebServer, 并啟動服務(wù)。 tomcat就是在這里啟動registerListeners
注冊事件監(jiān)聽器, 這里會把容器中的所有事件監(jiān)聽器類都注冊到SimpleApplicationEventMulticaster中。 并把在啟動這步之前積攢的事件消息都遍歷發(fā)布出去。finishBeanFactoryInitialization
完成容器初始化完成后的收尾方法。 這里會往容器中注入很多的類型轉(zhuǎn)換的bean。 并在這里實例化所有沒有設(shè)置lazy- init的finishRefresh
整個啟動過程的最后的方法, 這里會清空一些只在啟動中有用的緩存信息,發(fā)布啟動成功的事件。
在第五步的invokeBeanFactoryPostProcessors方法中, 除了會調(diào)BeanFactoryPostProcessors的實現(xiàn)類方法外還會調(diào)調(diào)用BeanDefinitionRegistryPostProcessor 類的postProcessBeanDefinitionRegistry方法,很多的框架就是通過這個方法來注入自己的bean, 比如Mybatis的 org.mybatis.spring.mapper.MapperScannerConfigurer
類。
總結(jié)
Refresh 是Spring啟動的重要方法, Spring的啟動整個周期都在這個方法中有提現(xiàn),上面的描述只是我自己的理解,不一定準(zhǔn)確完善。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
spring aop action中驗證用戶登錄狀態(tài)的實例代碼
本篇文章主要介紹了spring aop action中驗證用戶登錄狀態(tài)的實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07Maven管理多模塊應(yīng)用的統(tǒng)一版本號實現(xiàn)
本文主要介紹了Maven管理多模塊應(yīng)用的統(tǒng)一版本號實現(xiàn),使用versions-maven-plugin插件和占位符結(jié)合flatten-maven-plugin插件來實現(xiàn),感興趣的可以了解一下2024-12-12快速入門介紹Java中強(qiáng)大的String.format()
這篇文章主要給大家介紹了如何快速入門介紹Java中強(qiáng)大的String.format()的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03SpringBoot 監(jiān)控管理模塊actuator沒有權(quán)限的問題解決方法
這篇文章主要介紹了SpringBoot 監(jiān)控管理模塊actuator沒有權(quán)限的問題解決方法,需要的朋友可以參考下2017-12-12解決子線程中獲取不到HttpServletRequest對象的問題
這篇文章主要介紹了解決子線程中獲取不到HttpServletRequest對象的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07