Spring Boot應(yīng)用的整個啟動流程都封裝在SpringApplication.run方法中,其整個流程很長,但本質(zhì)上就是在Spring容器啟動的基礎(chǔ)上做了大量的擴展,按照這個思路來看看源碼:
項目啟動是通過SpringApplication的靜態(tài)run方法,那么,這個方法里面首先要創(chuàng)建一個SpringApplication對象實例,然后調(diào)用這個創(chuàng)建好的SpringApplication的實例方法
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
SpringApplication實例初始化完成并且完成設(shè)置后,就開始執(zhí)行run方法的邏輯了
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 1通過SpringFactoriesLoader加載所有的SpringApplicationRunListeners,并調(diào)用starting()方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 2 創(chuàng)建并配置當(dāng)前應(yīng)用將要使用的Environment配置文件(profile)和屬性(properties)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
// 3 SpringBoot應(yīng)用在啟動輸出的Banner 圖
Banner printedBanner = printBanner(environment);
// 4 根據(jù)是否是web項目,來創(chuàng)建不同的ApplicationContext容器
context = createApplicationContext();
// 5 通過SpringFactoriesLoader創(chuàng)建一系列FailureAnalyzer用于監(jiān)控(實現(xiàn)FailureAnalyzer接口的class)
analyzers = new FailureAnalyzers(context);
// 6 初始化ApplicationContext
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 7 調(diào)用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序
refreshContext(context);
// 8 查找當(dāng)前context中是否注冊有CommandLineRunner和ApplicationRunner,如果有則遍歷執(zhí)行它們。
afterRefresh(context, applicationArguments);
// 9 執(zhí)行所有SpringApplicationRunListener的finished()方法。
listeners.finished(context, null);
stopWatch.stop();
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
下面來對于上圖每一步進(jìn)行詳細(xì)的講解
1. 啟動所有SpringApplicationRunListeners
通過SpringFactoriesLoader查找并加載所有的SpringApplicationRunListeners,通過調(diào)用starting()方法通知所有的SpringApplicationRunListeners:應(yīng)用開始啟動了。SpringApplicationRunListeners其本質(zhì)上就是一個事件發(fā)布者,它在SpringBoot應(yīng)用啟動的不同時間點發(fā)布不同應(yīng)用事件類型(ApplicationEvent),如果有哪些事件監(jiān)聽者(ApplicationListener)對這些事件感興趣,則可以接收并且處理。
主要是啟動監(jiān)聽器用來監(jiān)聽后面各個階段的觸發(fā)的事件。源碼如下
public interface SpringApplicationRunListener {
// 運行run方法時立即調(diào)用此方法,可以用戶非常早期的初始化工作
void starting();
// Environment準(zhǔn)備好后,并且ApplicationContext創(chuàng)建之前調(diào)用
void environmentPrepared(ConfigurableEnvironment environment);
// ApplicationContext創(chuàng)建好后立即調(diào)用
void contextPrepared(ConfigurableApplicationContext context);
// ApplicationContext加載完成,在refresh之前調(diào)用
void contextLoaded(ConfigurableApplicationContext context);
// 當(dāng)run方法結(jié)束之前調(diào)用
void finished(ConfigurableApplicationContext context, Throwable exception);
}
2. 配置Environment
創(chuàng)建并配置當(dāng)前應(yīng)用將要使用的Environment,Environment用于描述應(yīng)用程序當(dāng)前的運行環(huán)境,其抽象了兩個方面的內(nèi)容:配置文件(profile)和屬性(properties),開發(fā)經(jīng)驗豐富的同學(xué)對這兩個東西一定不會陌生:不同的環(huán)境(eg:生產(chǎn)環(huán)境、預(yù)發(fā)布環(huán)境)可以使用不同的配置文件,而屬性則可以從配置文件、環(huán)境變量、命令行參數(shù)等來源獲取。因此,當(dāng)Environment準(zhǔn)備好后,在整個應(yīng)用的任何時候,都可以從Environment中獲取資源。
- 判斷Environment是否存在,不存在就創(chuàng)建(如果是web項目就創(chuàng)建StandardServletEnvironment,否則創(chuàng)建StandardEnvironment)
- 配置Environment:配置profile以及properties
- 調(diào)用SpringApplicationRunListener的environmentPrepared()方法,通知事件監(jiān)聽者:應(yīng)用的Environment已經(jīng)準(zhǔn)備好
3. 輸出Banner圖
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.6.RELEASE)
4. 根據(jù)是否是web項目,來創(chuàng)建不同的ApplicationContext容器
5. 創(chuàng)建一系列FailureAnalyzer
創(chuàng)建流程依然是通過SpringFactoriesLoader獲取到所有實現(xiàn)FailureAnalyzer接口的class,然后在創(chuàng)建對應(yīng)的實例。FailureAnalyzer用于分析故障并提供相關(guān)診斷信息。
6. 初始化ApplicationContext
- 將準(zhǔn)備好的Environment設(shè)置給ApplicationContext
- 遍歷調(diào)用所有的ApplicationContextInitializer的initialize()方法來對已經(jīng)創(chuàng)建好的ApplicationContext進(jìn)行進(jìn)一步的處理
- 調(diào)用SpringApplicationRunListener的contextPrepared()方法,通知所有的監(jiān)聽者:ApplicationContext已經(jīng)準(zhǔn)備完畢
- 將所有的bean加載到容器中
- 調(diào)用SpringApplicationRunListener的contextLoaded()方法,通知所有的監(jiān)聽者:ApplicationContext已經(jīng)裝載完畢
7 調(diào)用ApplicationContext的refresh()方法
調(diào)用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序,主要獲取到所有的BeanFactoryPostProcessor來對容器做一些額外的操作。BeanFactoryPostProcessor允許我們在容器實例化相應(yīng)對象之前,對注冊到容器的BeanDefinition所保存的信息做一些額外的操作
// 摘自refresh()方法中一句代碼
invokeBeanFactoryPostProcessors(beanFactory);
// 其實現(xiàn)類
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
......
}
8.查找當(dāng)前context中是否注冊有CommandLineRunner和ApplicationRunner,如果有則遍歷執(zhí)行它們。
9.執(zhí)行所有SpringApplicationRunListener的finished()方法。
這就是Spring Boot的整個啟動流程,其核心就是在Spring容器初始化并啟動的基礎(chǔ)上加入各種擴展點,這些擴展點包括:ApplicationContextInitializer、ApplicationListener以及各種BeanFactoryPostProcessor等等