1. 程式人生 > >springboot原始碼解析-管中窺豹系列之專案型別(二)

springboot原始碼解析-管中窺豹系列之專案型別(二)

# 一、前言 - 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專案: ``` ``` 歡迎關注公眾號:豐極,更多技術學習