目录
2.1、createApplicationContext()
一、简介
SpringBoot 项目之所以部署简单,其很大一部分原因就是因为不用自己折腾 Tomcat 相关配置,因为其本身内置了各种 Servlet 容器。SpringBoot 是怎么通过简单运行一个 main 函数,就能将容器启动起来,并将自身部署到其上 ,接下来,我们就从源码的角度分析一下SpringBoot启动过程中Tomcat是如果自动启动的。
二.内置Tomcat启动流程:
首先会实例化一个SpringApplication对象,看下其构造方法:
// 创建一个新的SpringApplication实例。应用程序上下文将从指定的主要来源加载bean
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 传递的resourceLoader为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 记录主方法的配置类名称
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推导出当前启动的项目的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化. 并将加载的数据存储在了 initializers 成员变量中。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 初始化监听器,并将加载的监听器实例对象存储在了listeners成员变量中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 反推出main方法所在的Class对象
this.mainApplicationClass = deduceMainApplicationClass();
}
这里详细说明了每个步骤做了哪些事情,这里我们主要关注跟Tomcat启动相关的即可:
// 推导出当前启动的项目的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// WebApplicationType.java
/**
* 根据classpath推导出web项目的类型。Servlet项目或者Reactive项目
*
* @return
*/
static WebApplicationType deduceFromClasspath() {
// 一些绑定的Java类的全类路径
// ClassUtils.isPresent(): 通过反射的方式获取对应的类型的Class对象,如果存在返回true,否则返回false
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
接着执行run()方法:
// 运行 Spring 应用程序,创建并刷新一个新的ApplicationContext
public ConfigurableApplicationContext run(String... args) {
// 创建一个任务执行观察器,用于统计run启动过程花了多少时间
StopWatch stopWatch = new StopWatch();
// 记录开始时间
stopWatch.start();
ConfigurableApplicationContext context = null;
// exceptionReporters集合用来存储异常报告器,用来报告SpringBoot启动过程的异常
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置了一个名为java.awt.headless的系统属性, 其实是想设置该应用程序,即使没有检测到显示器,也允许其启动. 对于服务器来说,是不需要显示器的,所以要这样设置.
configureHeadlessProperty();
// 从spring.factories配置文件中加载到EventPublishingRunListener对象并赋值给SpringApplicationRunListeners
// EventPublishingRunListener对象主要用来发布SpringBoot启动过程中内置的一些生命周期事件,标志每个不同启动阶段
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布启动事件
listeners.starting();
try {
// 创建ApplicationArguments对象,封装了args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 获取环境变量,包括系统变量、环境变量、命令行参数、默认变量等
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置需要忽略的BeanInfo信息
configureIgnoreBeanInfo(environment);
// 启动时控制台打印Banner
Banner printedBanner = printBanner(environment);
//1.跟tomcat相关
// 根据不同类型创建不同类型的spring容器Applicatio