SpringBoot修行之路-3.探祕SpringApplication
概述
一個標準的SpringBoot應用都具有如下類似程式碼:
這是我自己搭建的一個專案。裡面只有一個註解@SpringBootApplication。這個註解有倆個作用:
- 標明這是一個SpringBoot應用
- 開啟自動配置的功能
最後通過SpringApplication的run方法啟動應用。這是我們使用SpringBoot應用的的時候最常用的程式碼。
SpringApplication
執行專案中的啟動類的run方法後,就到了org.springframework.boot.SpringApplication的run方法。程式碼如下:
之後再繼續呼叫run方法。如下:
這裡建立了一個SpringApplication物件,然後執行run方法。關於SpringApplication物件屬性簡介,程式碼如下:
一些簡單的註釋我就直接放在截圖裡了,此處不再過多敘述。(ps:這個是我打斷點的時候截的圖)
自身的構造方法如下:
構造方法中初始化了一些屬性。webApplicationType的屬性具體實現是通過判斷是否存在指定的類來賦值。程式碼如下:
屬性mainApplicationClass是通過呼叫方法,判斷是哪個呼叫了main方法來推斷並設定專案main()方法啟動的主程式啟動類。程式碼如下:
簡單的看完了以後,我們關注的重點是Initializers和Listeners 屬性,倆者都是通過getSpringFactoriesInstances()方法獲得不同型別的陣列。
啟動原始碼的測試案例就可以看到這倆個的值。Initializers屬性的值如下:
Listenners屬性在SpringBoot原始碼的測試用例中如下圖:
這裡簡單說一下getSpringFactoriesInstances()方法。具體如下:
主要是通過Sping.factories的配置檔案來獲取對應的值。這裡names的值如下:org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
spring.factories部分內容截圖如下:
建立物件createSpringFactoriesInstances()方法的程式碼具體實現如下:
排序方法就不在多說,此處是實現了Conparator進行排序。
那麼此處例項化Application做了哪些事情呢?
- 將專案啟動類的class設定為屬性儲存起來
- 設定應用型別
- 設定初始化器
- 設定監聽器(初始化器和監聽器最後在run方法中都會呼叫)
- 設定mainApplicationClass屬性
建立完SpringApplication物件後,接下來看run方法。run方法整體邏輯較長。程式碼如下圖:
從上述程式碼中可以看出,專案初始化啟動大致包括以下幾個部分:
-
獲取並啟動監聽器
getRunListeners(args)和listeners.starting()方法主要用於獲取SpringApplication例項化過程中初始化的SpringApplicationRunListener監聽器,並執行。getRunListeners(args)的程式碼具體實現如下:
也是通過getSpringFactoriesInstances()方法來獲取一個SpringApplicationRunListener型別的監聽器。 -
根據SpringApplicationRunListeners以及引數來準備環境
prepareEnvironment(listeners,applicationArguments)方法主要用於對專案執行環境進行預設定,程式碼如下:
1. 根據不同的webApplicationType建立環境
2. 載入指定的配置檔案(包括多環境配置)
3. 通知監聽器,環境變數已經載入完成
4. 最後將環境繫結到SpringApplication
基本思路就是:建立環境,設定引數,通知監聽器,繫結到SpringApplication
然後,通過configureIgnoreBeanInfo(environment)方法排除一些不需要的執行環境 -
建立Spring容器
根據webApplicationType判斷,確定容器型別,如果是Servlet型別,則通過反射裝載對應的位元組碼,也就是AnnotationConfigServletWebServerApplication.程式碼如下:
-
Spring容器的前置處理
主要是在容器重新整理前的操作,比如設定容器環境,包括各種變數。最關鍵的操作是:將啟動類注入容器,為後續開啟自動配置奠定基礎。具體實現如下:
主要是對上下文進行一個預處理,比如監聽器的響應事件,載入資源,設定上下文環境等等。 -
重新整理容器
開啟重新整理Spring容器,通過refresh方法對整個IOC容器的初始化(包括bean資源的丁文,解析,註冊等),同時向JVM執行時註冊一個關機鉤子函式,在JVM關機時候能夠關閉上下文,除非已經關閉。具體實現如下:
注:第四步和第五步就是用之前的context初始化設定的context(應用上下文環境),environment(專案執行環境),listeners(監聽器),applicationArguments(專案引數),和printedBanner(專案圖示資訊)進行應用上下文的組裝配置,並重新整理配置。 -
Spring容器的後置處理
擴充介面,理由設計模式的模板方法,預設為空實現。如果有自定義需要,可以重新實現該方法。 -
發出結束執行的事件
獲取EventPublishingRunListener監聽器,並執行started方法,並且將建立的Spring容器傳進去,建立一個ApplicationStartedEvent事件,然後執行ConfigurableApplicationContext的publishEvent方法。也就是說在這裡是在Spring容器中釋出時間,前面的starting是直接向SpringApplication中的監聽器釋出啟動事件。 -
執行Runners
用於呼叫專案中自定義的執行器xxxRunners類,使得在專案啟動完成後立即執行一些特點的程式。其中SpringBoot提供倆種執行器介面,分別是ApplicationRunner和CommandLineRunner。在使用時,只需要自定義一個執行器類實現其中的一個介面並重寫對應的run方法介面,專案啟動後悔立即執行這些特定的程式。實現如下:
總結一下,run方法的執行過程中,發生了什麼事情。
第一步:獲取並啟動監聽器主要通過getSpringFactoriesInstances()方法來獲取一個SpringApplicationRunListeners型別的監聽器
第二步:根據SpringApplicationRunListeners以及引數來準備環境:
1.根據不同的webApplicationType建立環境
2.載入配置檔案
3.通知監聽器,環境變數準備完成
4.將環境繫結到SpringApplication
5.排除不需要的執行環境條件第三步:建立Spring容器。
通過webApplicationType的不同型別建立ApplicationContext
第四步:Spring容器的前置處理
主要是對上下文進行一個預處理,比如監聽器的響應時間,載入資源,設定上下文環境等等
第五步:重新整理容器
開啟重新整理容器,對整個IOC容器進行初始化,並註冊關機鉤子函式
第六步:後置處理
空實現。使用設計模式的模板方法,可以自定義實現
第七步:發出結束執行的事件
這裡主要是在Spring容器中釋出事件,和前面的starting方法不一樣,前面的是直接向SpringApplication中的監聽器釋出事件。
第八步:執行Runners
用於呼叫自定義的執行器,預設倆種執行器介面ApplicationRunner和CommandLineRunner。
相關文章
- SpringBoot 應用程式啟動過程探祕Spring Boot
- SpringBoot文件之SpringApplication的閱讀筆記Spring BootAPP筆記
- 探祕WKWebViewWebView
- SpringBoot 中 @SpringBootApplication註解背後的三體結構探祕Spring BootAPP
- Web列印探祕Web
- Cglib proxy探祕CGLib
- 探祕intern()方法
- 大資料運維集大成者修行之路大資料運維
- TaskContinuationsOptions.ExecuteSynchronously探祕
- 深度探祕.NET 5.0
- 探祕Java9Java
- SpringBoot啟動流程分析(一):SpringApplication類初始化過程Spring BootAPP
- Java 隨機數探祕Java隨機
- 【NIO系列】——之TCP探祕TCP
- SpringBoot之路(一)之初識SpringBootSpring Boot
- Springboot 加密方案探討Spring Boot加密
- MySQL InnoDB 儲存引擎探祕MySql儲存引擎
- JVM系列(三) - JVM物件探祕JVM物件
- Vue原始碼探祕(七)(createElement)Vue原始碼
- Vue原始碼探祕(九)(createComponent)Vue原始碼
- 探祕 Mach-O 檔案Mac
- PHP現代化框架探祕PHP框架
- 3. react-router-dom原始碼揭祕 - BrowserRouterReact原始碼
- Amazon Corretto技術細節探祕
- Elastic 探祕之遺落的珍珠AST
- MySQL探祕(八):InnoDB的事務MySql
- Koa:核心探祕與入坑指北
- RocketMQ 5.0 POP 消費模式探祕MQ模式
- 探索JAVA系列(一)探祕Java反射(Reflect)Java反射
- php 核心探祕之 PHP_FUNCTION 巨集PHPFunction
- 群邑報告:探祕越南農村
- RocketMQ(七):高效能探祕之MappedFileMQAPP
- Flinkx Logminer效能探測&優化之路優化
- 3. SpringBoot 整合第三方技術Spring Boot
- 探祕varian:優雅的釋出部署程式
- 探祕Android黑科技-ViewModel如何無視ConfigurationChangeAndroidView
- 資本深探:搜狐突然盈利的祕密
- SpringBoot開發祕籍 - 整合Graphql QuerySpring Boot