SpringBoot应用分类
SpringBoot2.0中的setWebApplicationTye(WebApplicationType)方法允许程序显式地设置Web应用的枚举类型。大体上分为两类:Web应用和非Web引用;
Web应用
Servlet Web (SERVLET)
- 表示SpringBoot应用是一个servlet的web程序,对应SpringMVC;并且需要启动对应的web容器支持如tomcat等
- 另外:需要在maven中添加
spring-boot-starter-web
依赖
Reactive Web(REACTIVE)
- 表示SpringBoot应用是一种非阻塞的web框架,对应spring-webflux,需要启动支持reactive的web容器;
- 需要在maven中添加
spring-boot-starter-webflux
依赖
非Web应用(NONE)
- 表示SpringBoot应用啥都没有,按照正常的代码走即可;不需要额外启动web容器如tomcat等
1、如何指定应用类型?
示例如下:
@SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SpringBootTestApplication.class)
// 设置SpringBoot应用的类型
.web(WebApplicationType.NONE)
.run(args);
}
}
2、默认SpringBoot应用类型
如果我不指定SpringBoot的应用类型呢?默认应该是什么?
一般情况下,我们的SpringBoot应用启动类是这样的:
/**
* 省略n个注解
*/
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
我们顺着SpringApplication.run(StartApplication.class, args);
往里跟源码,
经过四层进入到SpringApplicatioin
的构造函数中,其中通过WebApplicationType.deduceFromClasspath()
判断SpringBoot应用的类型默认应该为是什么;
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 根据classPath中类的内容判断SpringBoot应用的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
WebApplicationType
类的静态方法deduceFromClasspath()
源码如下:
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";
代码中频繁使用到ClassUtils.isPresent()
方法,通过其判断相应的类是否存在。
通过Class.forName()方法尝试加载某个类,如果能够加载成功,则证明这个类存在;
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) { try { forName(className, classLoader); return true; } ..... catch (Throwable ex) { return false; } }
- 反之发生异常则代表类不存在;
所以,对于deduceFromClasspath()
方法而言,本质上是通过webflux相关的类(DispatcherHandler)、Servlet相关的类(DispatcherServlet)是否存在来判断SpringBoot应用的类型;具体规则如下:
- 如果只能找到WebFlux相关的类,则SpringBoot应用类型为
REACTIVE
; - 如果找不到Servlet相关的上下文类,则SpringBoot应用类型为
NONE
; - 如果上述条件都不满足,则SpringBoot应用类型为
SERVLET
;
也就是说:我们可以理解为SpringBoot的应用程序默认类型是SERVLET
;