本文主要说明在调用 SpringApplication.run(…)
时,如何实例化 ConfigurableApplicationContext
,也即是如何选择 ConfigurableApplicationContext
的子类。
源码分析基于:
通常会像下面这样启动 Spring Boot 应用:
ClientInnerApplication
@SpringBootApplication
public class ClientInnerApplication {
public static void main(String[] args) {
SpringApplication.run(ClientInnerApplication.class, args);
}
}
SpringApplication.run
会返回一个 ConfigurableApplicationContext
,那么 ConfigurableApplicationContext
的实例类型是如何确定呢?通过以下源码:
SpringApplication.createApplicationContext()
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
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()
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
。
应用类型 | 类型说明 | 判断条件 | 具体子类 |
---|---|---|---|
SERVLET | 该应用程序应作为基于 Servlet 的 Web 应用程序运行,并应启动嵌入式 Servlet Web 服务器 | 存在 Servlet 和 ConfigurableWebApplicationContext | AnnotationConfigServlet WebServerApplicationContext |
REACTIVE | 该应用程序应作为 reactive Web 应用程序运行,并应启动嵌入式 reactive Web 服务器 | 存在 DispatcherHandler 并且不存在 DispatcherServlet 或 ServletContainer | AnnotationConfigReactive WebServerApplicationContext |
NONE | 该应用程序不应作为 Web 应用程序运行,也不应启动嵌入式 Web 服务器。 | 不是上面两种情况 | AnnotationConfig ApplicationContext |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。