一、SpringBoot 应用类型:
应用类型 |
| 关键类 | 加载服务器 | 备注 |
Web应用 | 响应式web应用(webflux)
| web.reactive.DispatcherHandler
| 加载启动内嵌的响应式web服务器 |
|
Servlet Web应用 | web.servlet.DispatcherServlet 或javax.servlet.Servlet
| 加载启动内嵌的web服务器 (如Tomcat) |
| |
普通应用 | java进程 |
| 普通java进程 |
|
二、推断应用的类型:
SpringBoot启动时,在创建SpringApplication对象时,会自动去识别并设置当前应用是普通web应用、响应式web应用还是非web应用。通过以下二程方式:判断应用类型。
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 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;
/**
* 1.通过ClassLoader查找该虚拟机jvm所加载的类中有没有特定的类。
* 2.特定的类:pom文件声明不同的依赖包(jar)里存在。
*
*/
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;
}
-
1、如果应用程序中存在org.springframework.web.reactive.DispatcherHandler这个类,则表示是一个响应式web应用,项目在启动时,需要去加载启动内嵌的响应式web服务器。
-
2、如果应用程序中既不存在javax.servlet.Servlet类,也不存在org.springframework.web.context.ConfigurableWebApplicationContext这个类,则表示当前应用不是一个web应用,启动时无需加载启动内嵌的web服务器。
-
3、除上述两种情况外,则表示当前应用是一个servlet的web应用,启动时需要加载启动内嵌的servlet的web服务器(比如Tomcat)。
三、推断并设置main方法的定义类(启动入口类)
SpringBoot是通过获取当前方法的调用栈信息,来判断当前main函数所在的类。找到入口函数。
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应用、响应式web应用、非web应用
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//查找并加载所有可用的ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//查找并加载所有可用的ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断并设置main方法的定义类(启动类)
this.mainApplicationClass = deduceMainApplicationClass();
}
/**
* 定义的类(包含main()方法),如myApplication.java,
* 1. myApplication.java本身也是一个普通@Configution类,需要加载类里的@Bean注入IOC容器
* 2. myApplication.java 默认情况下的扫描package是以myApplication.java所在的包。
*/
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}