@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
對于以上代碼,經常接觸SpringBoot、Cloud框架的開發者應該不陌生,新建SpringBoot項目生成的main方法入口,本章針對于SpringBoot的啟動流程進行分析。以上main方法比較突出 相比較普通的main方法 多出了@SpringBootApplication注解,以及run方法。我們分別對應這2個方向進行講解
核心注解
@SpringBootApplication
SpringBootApplication注解源碼
點擊SpringBootApplication注解我們可以進入該注解的源代碼中,可以看出改注解的組成部分由@SpringBootConfiguration注解組成、@EnableAutoConfiguration、ComponentScan注解組成。
- @SpringBootConfiguration:集成自Spring的@Configuration,作用相當于@Configuration注解,該注解在Spring3.0中增加,該注解的作用主要配合@Bean使用,配合使用通過JavaConfig的形式配置Bean。@Configuration注解相當于Spring當中的一個xml文件。
- @EnableAutoConfiguration注解
EnableAutoConfiguration我們可以看到該注解類引入了一個新的注解@Import,該注解對應的AutoConfigurationImportSelector.class類,
核心方法
該注解對應的核心方法可以通過閱讀發現,該方法作用于掃描META-INF/spring.factories配置文件,該配置文件可以看到其中包含了很多的AutoConfiguration都是基于默認配置。也就是說AutoConfigurationImportSelector該類的主要作用是針對于spring.factories的configuration進行掃描,然后針對其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的@Configuration配置掃描到ioc容器當中去
總結:@EnableAutoConfiguration的主要作用針對于,掃描spring.factories文件, 加載對應的configuration文件,把JavaConfig配置的@Bean掃描進入IOC容器當中
- @Import
- 該注解相當于xml文件當中的import,允許導入Configuration注解、importSelector和ImportBeanDefinitionRegistrar,以及普通的Component類
- @Conditional
- 該注解表示條件,只有滿足對應的條件的情況下,該類才會被加載進入IOC容器當中去,如常見的@ConditionalOnClass
總結:
@SpringBootConfiguration通過與@Bean結合完成Bean的JavaConfig配置
2. @ComponentScan 通過范圍掃描,掃描特定注解的類,將其注冊到Spring容器中 3. @EnableAutoConfiguration 通過掃描META-INF下面的spring.factories,并且結合@Condition 完成bean的注冊 4. @Import 通過導入的方式 將指定的class注冊解析到Spring容器
SpringApplication.run方法的執行流程
SpringApplication.run(Application.class, args);
對應的源碼實現
以上代碼我們可以看到,傳入了兩個參數第一個參數加載的類,第二個參數為啟動參數,
第一個方法為對應的main進入的方法,下面的方法為最終運行的重載方法,我們可以看到該方法執行了new SpringApplication最終還是會構造一個SpringApplication實例,然后在運行它的run方法。
- 該實例由構造函數創建,所以我們可以對應去查找SpringApplication對應的構造函數
SpringApplication的源碼
我們可以發現該構造函數執行了幾件事情、1
- deduceWebApplicationType推薦web的環境類型。
- setInitalizers設置初始化容器
- setListeners設置監聽器
- deduceMainApplicationClass推斷應用程序的入口
- deduceWebApplicationType,類型有3個REACTIVE \NONE\SERVLET
- NONE 表示不可以作為一個web應用,并且不能使用內置服務器
- SERVLET為一個基礎版本的web應用程序,使用內置的服務器
- REACTIVE為響應式編程,對應SpringBoot的webflux框架,嵌入響應式服務器
- setInitalizers初始化容器
setIntalizers初始化方法
* 我們可以看到該方法對應的執行了哪些操作,使用Set保存names去重,避免重復配置導致多次實例化 * 根據names進行去重,對實例進行排序,針對@Order注解配置順序 * 加載操作對應SpringFactoriesLoader里面進行加載。該方法會嘗試從類路徑下面的META-INF/spring.factories然后進行遍歷,讀取配置文件Key為ApplicationContextInitializer的value。確認被加載的類是確實ApplicationContextInitializer 的子類,然后得到構造器進行初始化,放入到實例列表中
- 設置監聽器 setListeners
- 實現方式和Initializer一樣
- 推斷應用程序入口類
- 通過構造一個運行時異常獲取,通過異常棧中方法名為main的棧幀來得到入口類的名字。
實例化完成開始執行run方法
啟動監聽
從上到下的流程分別為
- 啟動性能監聽StopWatch
- 設置系統屬性,允許該服務沒有鼠標顯示器也可以進行啟動
- 啟動監聽
- 根據SpringApplicationRunListeners以及參數來準備環境.
- 準備banner打印器,啟動springrunner的圖案
- 創建上下文
- 注冊異常分析器
- spring上下文前置處理,
- 上下文刷新
- 上下文后置處理
- 發出結束執行的時