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