public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//设置系统属性『java.awt.headless』,为true则启用headless模式支持
this.configureHeadlessProperty();
/*通过SpringFactoriesLoader检索META-INF/spring.factories,
找到声明的所有SpringApplicationRunListener的实现类并将其实例化,
之后逐个调用其started()方法,广播SpringBoot要开始执行了
*/
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//发布应用开始启动事件
listeners.starting();
Collection exceptionReporters;
try {
//初始化参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/*
创建并配置当前SpringBoot应用将要使用的Environment
(包括配置要使用的PropertySource以及Profile)
并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,
广播Environment准备完毕。
*/
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = this.printBanner(environment);
//创建应用上下文
context = this.createApplicationContext();
//通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,获取并实例化异常分析器
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
/*
为ApplicationContext加载environment,
之后逐个执行ApplicationContextInitializer的initialize()方法来进一步封装ApplicationContext,
并调用所有的SpringApplicationRunListener的contextPrepared()方法【EventPublishingRunListener只提供了一个空的contextPrepared()方法】,
之后初始化IoC容器,并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,
这里就包括通过@EnableAutoConfiguration导入的各种自动配置类。
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文
this.refreshContext(context);
//再一次刷新上下文,其实是空方法,可能是为了后续扩展。
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//发布应用已经启动的事件
listeners.started(context);
/*
遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
我们可以实现自己的ApplicationRunner或CommandLineRunner,来对SpringBoot的启动过程进行扩展。
*/
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
//应用已经启动完成的监听事件
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
总结下步骤为:
- 配置属性
- 获取监听器,发布应用开始启动事件
- 初始化输入参数
- 配置环境,输出banner
- 创建上下文
- 预处理上下文
- 刷新上下文
- 再刷新上下文
- 发布应用已经启动事件
- 发布应用启动完成事件
而启动Tomcat就是在第7步中“刷新上下文”;Tomcat的启动主要是初始化2个核心组件,连接器(Connector)和容器(Container),一个Tomcat实例就是一个Server,一个Server包含多个Service,也就是多个应用程序,每个Service包含多个连接器(Connetor)和一个容器(Container),而容器下又有多个子容器,按照父子关系分别为:Engine,Host,Context,Wrapper,其中除了Engine外,其余的容器都是可以有多个。