SpringBoot 應用程式啟動過程探祕
概述
說到接觸 SpringBoot 伊始,給我第一映像最深的是有兩個關鍵元素:
對照上面的典型程式碼,這個兩個元素分別是:
- @SpringBootApplication
- SpringApplication 以及 run() 方法
關於 @SpringBootApplication 註解的剖析已經在上文:《SpringBoot 中 @SpringBootApplication註解背後的三體結構探祕》 中完成了,其實它背後就是一個三體結構,只是 SpringBoot給了其一個包裝而已。那麼本文我們就來看看這個 SpringApplication 以及 run() 方法 到底是個什麼鬼,它背後又隱藏了哪些奧祕呢?
本文內容腦圖如下:
SpringApplication 驚鴻一瞥
SpringApplication 這個類應該算是 SpringBoot 框架 的“創新”產物了,原始的 Spring中並沒有這個類,SpringApplication 裡面封裝了一套 Spring 應用的啟動流程,然而這對使用者完全透明,因此我們上手 SpringBoot 時感覺簡潔、輕量。
一般來說預設的 SpringApplication 執行流程已經可以滿足大部分需求,但是 若使用者想幹預這個過程,則可以通過 SpringApplication 在流程某些地方開啟的 擴充套件點 來完成對流程的擴充套件,典型的擴充套件方案那就是使用 set 方法。
我們來舉一個栗子,把我們天天司空見慣的 SpringBoot 應用的啟動類來拆解一下寫出來:
@SpringBootApplication public class CodeSheepApplication { public static void main( String[] args ) { // SpringApplication.run( CodeSheepApplication.class args ); // 這是傳統SpringBoot應用的啟動,一行程式碼搞定,內部預設做了很多事 SpringApplication app = new SpringApplication( CodeSheepApplication.class ); app.setXXX( ... ); // 使用者自定的擴充套件在此 !!! app.run( args ); } }
這樣一拆解後我們發現,我們也需要先構造 SpringApplication 類物件,然後呼叫該物件的 run()
方法。那麼接下來就講講 SpringApplication 的構造過程 以及其 run()
方法的流程,搞清楚了這個,那麼也就搞清楚了SpringBoot應用是如何執行起來的!
SpringApplication 例項的初始化
我們對照程式碼來看:
四個關鍵的步驟已標註在圖中,分別解釋如下:
- ① 推斷應用的型別:建立的是 REACTIVE應用、SERVLET應用、NONE 三種中的某一種
- ② 使用
SpringFactoriesLoader
查詢並載入 classpath下META-INF/spring.factories
檔案中所有可用的ApplicationContextInitializer
- ③ 使用
SpringFactoriesLoader
查詢並載入 classpath下META-INF/spring.factories
檔案中的所有可用的ApplicationListener
- ④ 推斷並設定 main方法的定義類
SpringApplication 的run()方法探祕
先看看程式碼長啥樣子:
各個主要步驟我已經標註在上圖之中了,除此之外,我也按照自己的理解畫了一個流程圖如下所示,可以對照數字標示看一下:
我們將各步驟總結精煉如下:
-
通過
SpringFactoriesLoader
載入META-INF/spring.factories
檔案,獲取並建立SpringApplicationRunListener
物件 -
然後由
SpringApplicationRunListener
來發出 starting 訊息 -
建立引數,並配置當前 SpringBoot 應用將要使用的 Environment
-
完成之後,依然由
SpringApplicationRunListener
來發出 environmentPrepared 訊息 -
建立
ApplicationContext
-
初始化
ApplicationContext
,並設定 Environment,載入相關配置等 -
由
SpringApplicationRunListener
來發出contextPrepared
訊息,告知SpringBoot 應用使用的ApplicationContext
已準備OK -
將各種 beans 裝載入
ApplicationContext
,繼續由SpringApplicationRunListener
來發出 contextLoaded 訊息,告知 SpringBoot 應用使用的ApplicationContext
已裝填OK -
refresh ApplicationContext,完成IoC容器可用的最後一步
-
由
SpringApplicationRunListener
來發出 started 訊息 -
完成最終的程式的啟動
-
由
SpringApplicationRunListener
來發出 running 訊息,告知程式已執行起來了
至此,全流程結束!