1. 程式人生 > >SpringBoot 應用程式啟動過程探祕

SpringBoot 應用程式啟動過程探祕

概述

說到接觸 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 例項的初始化

我們對照程式碼來看:

SpringApplication 例項的初始化程式碼

四個關鍵的步驟已標註在圖中,分別解釋如下:

  •  推斷應用的型別:建立的是 REACTIVE應用、SERVLET應用、NONE 三種中的某一種

推斷應用的型別

  •  使用 SpringFactoriesLoader查詢並載入 classpath下 META-INF/spring.factories檔案中所有可用的 ApplicationContextInitializer

ApplicationContextInitializer 載入

  •  使用 SpringFactoriesLoader查詢並載入 classpath下 META-INF/spring.factories檔案中的所有可用的 ApplicationListener

ApplicationListener 載入

  •  推斷並設定 main方法的定義類

推斷並設定main方法的定義類

SpringApplication 的run()方法探祕

先看看程式碼長啥樣子:

SpringApplication 的run()方法背後的奧祕

各個主要步驟我已經標註在上圖之中了,除此之外,我也按照自己的理解畫了一個流程圖如下所示,可以對照數字標示看一下:

SpringBoot 應用啟動流程圖

我們將各步驟總結精煉如下:

  1. 通過 SpringFactoriesLoader 載入 META-INF/spring.factories 檔案,獲取並建立 SpringApplicationRunListener物件

  2. 然後由 SpringApplicationRunListener 來發出 starting 訊息

  3. 建立引數,並配置當前 SpringBoot 應用將要使用的 Environment

  4. 完成之後,依然由 SpringApplicationRunListener 來發出 environmentPrepared 訊息

  5. 建立 ApplicationContext

  6. 初始化 ApplicationContext,並設定 Environment,載入相關配置等

  7. 由 SpringApplicationRunListener 來發出 contextPrepared 訊息,告知SpringBoot 應用使用的 ApplicationContext已準備OK

  8. 將各種 beans 裝載入 ApplicationContext,繼續由 SpringApplicationRunListener 來發出 contextLoaded 訊息,告知 SpringBoot 應用使用的 ApplicationContext 已裝填OK

  9. refresh ApplicationContext,完成IoC容器可用的最後一步

  10. 由 SpringApplicationRunListener 來發出 started 訊息

  11. 完成最終的程式的啟動

  12. 由 SpringApplicationRunListener 來發出 running 訊息,告知程式已執行起來了

至此,全流程結束!