前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringApplication 启动时如何选择 ConfigurableApplicationContext

SpringApplication 启动时如何选择 ConfigurableApplicationContext

原创
作者头像
安宁
修改2020-07-15 11:23:44
3.3K0
修改2020-07-15 11:23:44
举报

本文主要说明在调用 SpringApplication.run(…​) 时,如何实例化 ConfigurableApplicationContext,也即是如何选择 ConfigurableApplicationContext 的子类。

1. 版本说明

源码分析基于:

  • spring-boot:2.3.0

2. web 应用类型

通常会像下面这样启动 Spring Boot 应用:

ClientInnerApplication

代码语言:javascript
复制
@SpringBootApplication
public class ClientInnerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientInnerApplication.class, args);
    }
}

SpringApplication.run 会返回一个 ConfigurableApplicationContext,那么 ConfigurableApplicationContext 的实例类型是如何确定呢?通过以下源码:

SpringApplication.createApplicationContext()

代码语言:javascript
复制
protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
            case SERVLET:
                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                break;
            case REACTIVE:
                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                break;
            default:
                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

可以看出:是通过 webApplicationType 判断的。不同的 webApplicationType 选择不同的 ConfigurableApplicationContext 子类。那么 webApplicationType 的值是怎么确定的呢?通过以下源码:

SpringApplication

代码语言:javascript
复制
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

可以看出:webApplicationType 是在 SpringApplication 实例化时,获取了 WebApplicationType.deduceFromClasspath() 的返回值。那么 WebApplicationType.deduceFromClasspath() 是如何选择 WebApplicationType 的呢?通过以下源码:

WebApplicationType.deduceFromClasspath()

代码语言:javascript
复制
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;
}

可以看出:WebApplicationType.deduceFromClasspath() 会根据运行时环境中是否存在应用上下文关联的特定类返回不同的 WebApplicationType

3. 总结

应用类型

类型说明

判断条件

具体子类

SERVLET

该应用程序应作为基于 Servlet 的 Web 应用程序运行,并应启动嵌入式 Servlet Web 服务器

存在 Servlet 和 ConfigurableWebApplicationContext

AnnotationConfigServlet WebServerApplicationContext

REACTIVE

该应用程序应作为 reactive Web 应用程序运行,并应启动嵌入式 reactive Web 服务器

存在 DispatcherHandler 并且不存在 DispatcherServlet 或 ServletContainer

AnnotationConfigReactive WebServerApplicationContext

NONE

该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器。

不是上面两种情况

AnnotationConfig ApplicationContext

  • Servlet:javax.servlet.Servlet
  • ConfigurableWebApplicationContext:org.springframework.web.context.ConfigurableWebApplicationContext
  • AnnotationConfigServletWebServerApplicationContext:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
  • DispatcherHandler:org.springframework.web.reactive.DispatcherHandler
  • DispatcherServlet:org.springframework.web.servlet.DispatcherServlet
  • ServletContainer:org.glassfish.jersey.servlet.ServletContainer
  • AnnotationConfigReactiveWebServerApplicationContext:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
  • AnnotationConfigApplicationContext:org.springframework.context.annotation.AnnotationConfigApplicationContext

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 版本说明
  • 2. web 应用类型
  • 3. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档