一、前言
- Springboot 源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
- 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的 springboot 源码管中窥豹系列。
二、我的项目类型
这一节咱们先讨论一下 springboot 我的项目的怎么主动加载 applicationcontext 实现类的。
- 以前的 spring 的我的项目,都是 xml 加载 bean,罕用的都是 XmlWebApplicationContext 实现类
- 起初呈现注解的模式,根本用 AnnotationConfigWebApplicationContext 实现类
- 起初又呈现响应式编程 reactive
那 springboot 用的是哪一种呢?
三、源码解读
先说论断:对于类型的抉择,springboot 是依据 class 来判断的。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
...
this.webApplicationType = WebApplicationType.deduceFromClasspath();
...
}
- 咱们从 SpringApplication 的构造函数开始看起
- 构造函数外面有段代码:是确定类型的
咱们先看类型:
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";
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;
}
- 第一段 if, 如果存在 reactive 包的 DispatcherServlet,同时不存在 jersey 和 mvc 的 DispatcherHandler, 就是 REACTIVE
- 第二段循环,不存在 Servlet 或者 ConfigurableWebApplicationContext,就是 none
- 剩下的就是咱们相熟的 SERVLET
类型确定之后,咱们看 SpringApplication 的 run 办法:
public ConfigurableApplicationContext run(String... args) {
...
try {
...
context = createApplicationContext();
...
} catch (Throwable ex) {...}
...
return context;
}
ApplicationContext 实现类就是在 createApplicationContext()外面确定的
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
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);
}
依据类型加载不同的 class:
- 如果是 SERVLET:AnnotationConfigServletWebServerApplicationContext
- 如果是 REACTIVE:
AnnotationConfigReactiveWebServerApplicationContext
- default:AnnotationConfigApplicationContext
至此,高深莫测了,想要不同的我的项目类型,增加对应的 jar 包,springboot 主动帮你抉择对应的 ApplicationContext 实现类
如果是一般的 web 我的项目:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果是 reactive 我的项目:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
如果是非 web 我的项目:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
欢送关注公众号:丰极,更多技术学习分享。