概 述
在Java後端開發領域,大名鼎鼎的Spring Boot框架想必大家都用過。
用過Spring Boot的應該都知道,在項目啓動入口的主類main()方法裏,一句簡簡單單的
SpringApplication.run( ... );
便開啓了項目的啓動運行之路。
那麼本文我們就來看看這個 SpringApplication 以及 run() 方法 到底是個什麼鬼,它背後又隱藏了哪些奧祕呢?
SpringApplication
SpringApplication這個類應該算是 Spring Boot 框架 本身的“創新”產物了,因爲原始的Spring框架中並沒有這個類,SpringApplication裏面封裝了一套Spring應用的啓動流程,然而這對用戶完全透明,因此我們上手 Spring Boot 時感覺簡潔且輕量。
一般來說默認的SpringApplication執行流程已經可以滿足大部分需求,但是 若用戶想幹預這個過程,則可以通過SpringApplication在流程某些地方開啓的擴展點來完成對流程的擴展,典型的擴展方案那就是使用set方法。
我們來舉一個栗子,把我們天天司空見慣的 Spring Boot 應用的啓動類來拆解一下寫出來:
@SpringBootApplicationpublic class CodeSheepApplication { public static void main( String[] args ) { // SpringApplication.run( CodeSheepApplication.class args ); // 這是傳統Spring Boot應用的啓動,一行代碼搞定,內部默認做了很多事 SpringApplication app = new SpringApplication( CodeSheepApplication.class ); app.setXXX( ... ); // 用戶自定的擴展在此 !!! app.run( args ); }}
這樣一拆解後我們發現,我們也需要先構造SpringApplication類對象,然後調用該對象的run()方法。
那麼接下來就聊聊SpringApplication的構造過程 以及其run()方法的流程,搞清楚了這個,那麼也就搞清楚了Spring Boot應用是如何運行起來的了。
SpringApplication實例的初始化
還是先對照代碼來看:
四個關鍵的步驟已標註在圖中,分別解釋如下:
①推斷應用的類型:創建的是REACTIVE應用、SERVLET應用、NONE 三種中的某一種
②使用SpringFactoriesLoader查找並加載classpath下META-INF/spring.factories文件中所有可用的ApplicationContextInitializer
③使用SpringFactoriesLoader查找並加載classpath下META-INF/spring.factories文件中的所有可用的ApplicationListener
④推斷並設置main方法的定義類
SpringApplication的run()方法探祕
先看看代碼長啥樣子:
我們將各步驟總結精煉如下:
1.通過SpringFactoriesLoader加載META-INF/spring.factories文件,獲取並創建SpringApplicationRunListener對象
2.然後由SpringApplicationRunListener來發出starting消息
3.創建參數,並配置當前SpringBoot應用將要使用的Environment
4.完成之後,依然由SpringApplicationRunListener來發出environmentPrepared消息
5.創建ApplicationContext
6.初始化ApplicationContext,並設置Environment,加載相關配置等
7.由SpringApplicationRunListener來發出contextPrepared消息,告知Spring Boot 應用使用的ApplicationContext已準備OK
8.將各種beans裝載入ApplicationContext,繼續由SpringApplicationRunListener來發出contextLoaded消息,告知 Spring Boot 應用使用的ApplicationContext已裝填OK
9.refresh ApplicationContext,完成IoC容器可用的最後一步
10由SpringApplicationRunListener來發出started消息
11.調用callRunners(...)方法,讓實現了ApplicationRunner和CommandLineRunner接口類的run方法得以執行,用於在 Spring 應用上下文準備完畢後,執行一些額外操作。從而完成最終的程序的啓動。
12.由SpringApplicationRunListener來發出running消息,告知程序已運行起來了
至此,全流程結束。