Spring Boot技术内幕:架构设计与实现原理
上QQ阅读APP看书,第一时间看更新

3.4 Web应用类型推断

完成变量赋值之后,在SpringApplication的构造方法中便调用了WebApplicationType的deduceFromClasspath方法来进行Web应用类型的推断。SpringApplication构造方法中的相关代码如下。


public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ...
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    ...
}

该行代码调用了WebApplicationType的deduceFromClasspath方法,并将获得的Web应用类型赋值给私有成员变量webApplicationType。

WebApplicationType为枚举类,它定义了可能的Web应用类型,该枚举类提供了三类定义:枚举类型、推断类型的方法和用于推断的常量。枚举类型包括非Web应用、基于SERVLET的Web应用和基于REACTIVE的Web应用,代码如下。


public enum WebApplicationType {
    // 非Web应用类型
    NONE,
    // 基于SERVLET的Web应用类型
    SERVLET,
    // 基于REACTIVE的Web应用类型
    REACTIVE;
    ...
}

WebApplicationType内针对Web应用类型提供了两个推断方法:deduceFromClasspath方法和deduceFromApplicationContext方法。在此我们使用了deduceFromClasspath方法,下面重点分析该方法的实现。


public enum WebApplicationType {
    ...
    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";

// 基于classpath的Web应用类型推断,核心实现方法为ClassUtils.isPresent
    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;
    }
    ...
}

方法deduceFromClasspath是基于classpath中类是否存在来进行类型推断的,就是判断指定的类是否存在于classpath下,并根据判断的结果来进行组合推断该应用属于什么类型。deduceFromClasspath在判断的过程中用到了ClassUtils的isPresent方法。isPresent方法的核心机制就是通过反射创建指定的类,根据在创建过程中是否抛出异常来判断该类是否存在。

通过上面的源代码,我们可以看到deduceFromClasspath的推断逻辑如下。

·当DispatcherHandler存在,并且DispatcherServlet和ServletContainer都不存在,则返回类型为WebApplicationType.REACTIVE。

·当SERVLET或ConfigurableWebApplicationContext任何一个不存在时,说明当前应用为非Web应用,返回WebApplicationType.NONE。

·当应用不为REACTIVE Web应用,并且SERVLET和ConfigurableWebApplicationContext都存在的情况下,则为SERVLET的Web应用,返回WebApplicationType.SERVLET。