文章目录
-
- SpringBoot启动运行流程
-
- 1. 调用构造函数
- 2. 执行run方法
-
- 2.1 程序计时开始
- 2.2 设置java.awt.headless系统变量
- 2.3 加载所有SpringApplicationRunListener
- 2.4 发布starting事件
- 2.5 准备运行环境
- 2.6 配置spring.beaninfo.ignore属性
- 2.7 打印banner
- 2.8 初始化ConfigurableApplicationContext
- 2.9 初始化SpringBootExceptionReporter
- 2.10 准备context
- 2.11 refresh context
- 2.12 after refresh
- 2.13 程序停止计时
- 2.14 发布started事件
- 2.15 回调
- 2.16 发布running事件
SpringBoot启动运行流程
SpringBoot有两种启动方式:
- 第一种方式:通过调用SpringApplication的静态方法run方法启动
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 第二种方式:通过SpringApplication实例调用run方法启动
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(App.class);
ConfigurableApplicationContext context = springApplication.run(args);
context.close();
}
}
而调用静态方法run方法,底层其实也是创建SpringApplication对象的方式。接下来就从创建SpringApplication实例开始梳理一下SpringBoot的启动运行流程。
1. 调用构造函数
@SuppressWarnings({
"unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
//1.1 启动传入源非空判断,如以上示例中传入的App.class
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//1.2 推断web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//1.3 加载所有classpath下面的META-INF/spring.factories中配置的ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//1.4 加载所有classpath下面的META-INF/spring.factories中配置的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//1.5 推断main方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1 源非空判断
调用构造函数时,传入源进行非空判断,如以上示例中传入的App.class。
1.2 推断web应用类型
static WebApplicationType deduceFromClasspath() {
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;
}
private static final String[] SERVLET_INDICATOR_CLASSES = {
"javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
根据源码,这里提供三种应用类型:
REACTIVE
—Reactor编程模型的非阻塞异步Web编程框架WebFlux;
SERVLET
—运行在Servlet容器上;
NONE
—非web应用。
通过类路径下的是否存在相应的类判断具体的应用程序类型:
REACTIVE:org.springframework.web.reactive.DispatcherHandler
SERVLET:org.springframework.web.servlet.DispatcherServlet,org.glassfish.jersey.servlet.ServletContainer
NONE:javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext
1.3 加载ApplicationContextInitializer
加载所有classpath下面的META-INF/spring.factories中配置的ApplicationContextInitializer。
ApplicationContextInitializer接口使用,可参见文章:https://blog.csdn.net/qq_35006663/article/details/102265276
1.4 加载ApplicationListener
加载所有classpath下面的META-INF/spring.factories中配置的ApplicationListener。
ApplicationListener接口使用,可参见文章:https://blog.csdn.net/qq_35006663/article/details/101039761
1.5 推断main方法所在的类
找到项目中的main方法所在的类,即启动类。
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTrac