1. main
入口
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
2. SpringApplication#run
静态方法调用
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
由此可见,一个SpringApplication
的启动主要是 :
- 构造一个
SpringApplication
对象;- 构造函数参数是包含
main
方法的应用程序入口类;
- 构造函数参数是包含
- 调用所构建
SpringApplication
对象的run
方法;run
方法参数是应用程序入口方法main
的参数;
2.1. SpringApplication
构造函数
// SpringApplication 代码片段
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 检测Web应用的类型,针对当前粒子项目,这里检测到的结果是 :
// WebApplicationType.REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载并初始化类型为 ApplicationContextInitializer 的应用程序上下文初始化器,
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 加载并初始化类型为 ApplicationListener 的应用程序事件监听器,
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 构造一个RuntimeException对象,从异常堆栈中分析包含`main` 方法的应用程序
// 入口类,并记录到 this.mainApplicationClass, 在我们的例子应用中,它就是
// practice.webflux.Application
this.mainApplicationClass = deduceMainApplicationClass();
}
在SpringApplication
构造函数中,能体现当前应用是一个Spring WebFlux
应用最关键的步骤要数this.webApplicationType = WebApplicationType.deduceFromClasspath()
了,因为这一步检测到当前应用环境是WebApplicationType.REACTIVE
,我们来看其实现:
// WebApplicationType 代码片段
package org.springframework.boot;
import org.springframework.util.ClassUtils;
public enum WebApplicationType {
/**
* The application should not run as a web application and should not start an
* embedded web server.
*/
NONE,
/**
* The application should run as a servlet-based web application and should start an
* embedded servlet web server.
*/
SERVLET,
/**
* The application should run as a reactive web application and should start an
* embedded reactive web server.
*/
REACTIVE;
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";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS =
"org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS =
"org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
// 从 classpath 上关键类的存在性判断当前应用中开发人员要使用什么样的Web环境
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
// 如果类 org.springframework.web.reactive.DispatcherHandler 存在于 classpath,
// 并且类 org.springframework.web.servlet.DispatcherServlet 和类
// org.glassfish.jersey.servlet.ServletContainer 都不存在于 classpath,
// 则推断这是一个 Reactive Web 环境,也就是 Spring WebFlux 环境
return WebApplicationType.REACTIVE;
}
// 现在已经检测到当前环境不是 Spring WebFlux 环境,接下来判断是否是
// Servlet Web 环境,通过检测 Servlet 特征类来实现
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
// 如果以下两个 Servlet 特征类之一不存在于classpath,即认为当前环境
// 不是 Servlet 环境,之前也已经判断了不是 Reactive 环境,所以这里
// 推断认为是非Web环境
return WebApplicationType.NONE;
}
}
// 经过以上的推断,如果逻辑能够走到这里,就认为是 Servlet Web 环境
return WebApplicationType.SERVLET;
}
// 省略其他无关代码 ...
}
从以上WebApplicationType#deduceFromClasspath
方法的实现来看,它是根据classpath
上针对不同Web
环境的特征类的存在性来判断当前应用的Web
环境的。当开发人员通过pom.xml
引入了依赖spring-boot-starter-webflux
时,实际上会导致classpath
上会存在如下依赖包 :
而Reactive Web
环境的特征类org.springframework.web.reactive.DispatcherHandler
,正存在于jar
包org.springframework:spring-webflux:5.1.8.RELEASE
。基于这些信息,WebApplicationType#deduceFromClasspath推断出当前应用正在使用
Reactive Web`环境。