SpringBoot 如何推导出应用类型

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应用是一个普通的java应用;不需要额外启动web容器。

1、如何指定应用类型

示例如下:

@SpringBootApplication
public class SpringBootApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(SpringBootTestApplication.class)
            // 设置SpringBoot应用的类型    
            .web(WebApplicationType.NONE)
            .run(args);
    }
}

2、SpringBoot应用类型

一般情况下,我们的SpringBoot应用启动类是这样的:

@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应用的类型;具体规则如下:

  1. 如果只能找到WebFlux相关的类,则SpringBoot应用类型为REACTIVE
  2. 如果找不到Servlet相关的上下文类,则SpringBoot应用类型为NONE
  3. 如果上述条件都不满足,则SpringBoot应用类型为SERVLET

也就是说,SpringBoot应用程序的默认类型是SERVLET

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值