public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//設(shè)置系統(tǒng)屬性『java.awt.headless』,為true則啟用headless模式支持
this.configureHeadlessProperty();
/*通過SpringFactoriesLoader檢索META-INF/spring.factories,
找到聲明的所有SpringApplicationRunListener的實(shí)現(xiàn)類并將其實(shí)例化,
之后逐個(gè)調(diào)用其started()方法,廣播SpringBoot要開始執(zhí)行了
*/
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//發(fā)布應(yīng)用開始啟動(dòng)事件
listeners.starting();
Collection exceptionReporters;
try {
//初始化參數(shù)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/*
創(chuàng)建并配置當(dāng)前SpringBoot應(yīng)用將要使用的Environment
(包括配置要使用的PropertySource以及Profile)
并遍歷調(diào)用所有的SpringApplicationRunListener的environmentPrepared()方法,
廣播Environment準(zhǔn)備完畢。
*/
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = this.printBanner(environment);
//創(chuàng)建應(yīng)用上下文
context = this.createApplicationContext();
//通過*SpringFactoriesLoader*檢索*META-INF/spring.factories*,獲取并實(shí)例化異常分析器
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/*
為ApplicationContext加載environment,
之后逐個(gè)執(zhí)行ApplicationContextInitializer的initialize()方法來進(jìn)一步封裝ApplicationContext,
并調(diào)用所有的SpringApplicationRunListener的contextPrepared()方法【EventPublishingRunListener只提供了一個(gè)空的contextPrepared()方法】,
之后初始化IoC容器,并調(diào)用SpringApplicationRunListener的contextLoaded()方法,廣播ApplicationContext的IoC加載完成,
這里就包括通過@EnableAutoConfiguration導(dǎo)入的各種自動(dòng)配置類。
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文
this.refreshContext(context);
//再一次刷新上下文,其實(shí)是空方法,可能是為了后續(xù)擴(kuò)展。
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//發(fā)布應(yīng)用已經(jīng)啟動(dòng)的事件
listeners.started(context);
/*
遍歷所有注冊(cè)的ApplicationRunner和CommandLineRunner,并執(zhí)行其run()方法。
我們可以實(shí)現(xiàn)自己的ApplicationRunner或CommandLineRunner,來對(duì)SpringBoot的啟動(dòng)過程進(jìn)行擴(kuò)展。
*/
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
//應(yīng)用已經(jīng)啟動(dòng)完成的監(jiān)聽事件
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
總結(jié)下步驟為:
- 配置屬性
- 獲取監(jiān)聽器,發(fā)布應(yīng)用開始啟動(dòng)事件
- 初始化輸入?yún)?shù)
- 配置環(huán)境,輸出banner
- 創(chuàng)建上下文
- 預(yù)處理上下文
- 刷新上下文
- 再刷新上下文
- 發(fā)布應(yīng)用已經(jīng)啟動(dòng)事件
- 發(fā)布應(yīng)用啟動(dòng)完成事件
而啟動(dòng)Tomcat就是在第7步中“刷新上下文”;Tomcat的啟動(dòng)主要是初始化2個(gè)核心組件,連接器(Connector)和容器(Container),一個(gè)Tomcat實(shí)例就是一個(gè)Server,一個(gè)Server包含多個(gè)Service,也就是多個(gè)應(yīng)用程序,每個(gè)Service包含多個(gè)連接器(Connetor)和一個(gè)容器(Container),而容器下又有多個(gè)子容器,按照父子關(guān)系分別為:Engine,Host,Context,Wrapper,其中除了Engine外,其余的容器都是可以有多個(gè)。