springboot原始碼解析-管中窺豹系列之專案型別(二)
阿新 • • 發佈:2021-01-08
# 一、前言
- Springboot原始碼解析是一件大工程,逐行逐句的去研究程式碼,會很枯燥,也不容易堅持下去。
- 我們不追求大而全,而是試著每次去研究一個小知識點,最終聚沙成塔,這就是我們的springboot原始碼管中窺豹系列。
![ 簡介 ](https://zhangbin1989.gitee.io/blog/picture/zb0018_springsour/springboot_source_0.png)
# 二、專案型別
這一節我們先討論一下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專案:
```
```
如果是reactive專案:
```
```
如果是非web專案:
```
```
歡迎關注公眾號:豐極,更多技術學習