SpringBoot啟動(dòng)之SpringApplication初始化詳解
SpringApplication初始化

當(dāng)啟動(dòng)SpringBoot應(yīng)用后,經(jīng)過(guò)兩步,會(huì)進(jìn)入到new SpringApplication(primarySources).run(args)。
1、primarySources參數(shù)
primarySources參數(shù)實(shí)際為Spring Boot應(yīng)用上下文的Configuration Class,在后面掃描配置類(lèi)時(shí)起作用。
2、SpringApplication初始化
SpringApplication對(duì)象的初始化

具體操作包括:
- 首先初始化資源加載器,默認(rèn)為null;斷言判斷主要資源類(lèi)不能為null,否者報(bào)錯(cuò)。
- 然后將主資源類(lèi)primarySources存儲(chǔ)到SpringApplication對(duì)象Set類(lèi)型的primarySources屬性中。
- 推斷當(dāng)前 WEB 應(yīng)用類(lèi)型,一共有三種:NONE,SERVLET,REACTIVE;默認(rèn)是SERVLET。
- 加載Spring應(yīng)用上下文初始化器:從"META-INF/spring.factories"文件中讀取ApplicationContextInitializer類(lèi)的實(shí)例名稱(chēng)集合,然后進(jìn)行Set去重、利用反射實(shí)例化對(duì)象,最后按照Order排序后,賦值到SpringApplication的List類(lèi)型的initializers屬性上,一共7個(gè)。
- 加載Spring應(yīng)用事件監(jiān)聽(tīng)器:從"META-INF/spring.factories"文件中讀取ApplicationListener類(lèi)的實(shí)例名稱(chēng)集合,然后進(jìn)行Set去重、利用反射實(shí)例化對(duì)象,最后按照Order排序后,賦值到SpringApplication的List類(lèi)型的listeners屬性上,一共11個(gè)。
- 推斷主入口應(yīng)用類(lèi):通過(guò)當(dāng)前調(diào)用棧的解析,獲取Main方法所在類(lèi),并賦值給SpringApplication的mainApplicationClass屬性。
1)推斷Web應(yīng)用類(lèi)型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
這里推斷的Web應(yīng)用類(lèi)型是默認(rèn)的,我們還可以手動(dòng)的再通過(guò)setWebApplicatioinType(WebApplicationType)方法進(jìn)行調(diào)整。這里通過(guò)檢查當(dāng)前ClassLoader下基準(zhǔn)Class的存在性來(lái)推斷Web應(yīng)用類(lèi)型。
public enum WebApplicationType {
NONE,
SERVLET,
REACTIVE;
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() {
// 1. 如果`DispatcherHandler`存在,并且`DispatcherServlet`和`ServletContainer`不存在時(shí),Web應(yīng)用類(lèi)型為REACTIVE;
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 2. 如果`Servlet`和`ConfigurableWebApplicationContext`不存在,則當(dāng)前應(yīng)用為非Web引應(yīng)用,即NONE。
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 3.當(dāng)Spring WebFlux和Spring Web MVC同時(shí)存在時(shí),Web應(yīng)用依舊是SERVLET。
return WebApplicationType.SERVLET;
}
....
}WEB 應(yīng)用類(lèi)型,一共有三種:NONE,SERVLET,REACTIVE。
deduceFromClasspath()方法利用ClassUtils.isPresent(String, ClassLoader)方法依次判斷reactive.DispatcherHandler、ConfigurableWebApplicationContext、Servlet、servlet.DispatcherServlet的存在性組合情況,從而判斷Web 引用類(lèi)型,具體邏輯如下:
- 如果DispatcherHandler存在,并且DispatcherServlet和ServletContainer不存在時(shí),即:Spring Boot僅依賴(lài)WebFlux時(shí),Web應(yīng)用類(lèi)型為REACTIVE;
- 如果Servlet和ConfigurableWebApplicationContext不存在,則當(dāng)前應(yīng)用為非Web應(yīng)用,即NONE。因?yàn)檫@兩個(gè)API是Spring Web MVC必須的依賴(lài)。
- 當(dāng)Spring WebFlux和Spring Web MVC同時(shí)存在時(shí),Web應(yīng)用類(lèi)型依舊是SERVLET。
2)加載Spring應(yīng)用上下文初始化器ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
這個(gè)過(guò)程包括兩個(gè)動(dòng)作:
1. getSpringFactoriesInstances(ApplicationContextInitializer.class)從"META-INF/spring.factories"文件中讀取ApplicationContextInitializer類(lèi)的實(shí)例名稱(chēng)集合,然后進(jìn)行Set去重、利用反射實(shí)例化對(duì)象,最后按照Order排序。
2. setInitializers(Collection)將Collection賦值到SpringApplication的List類(lèi)型的initializers屬性上,一共7個(gè)。
3)加載Spring事件應(yīng)用監(jiān)聽(tīng)器ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
這個(gè)過(guò)程和加載Spring應(yīng)用上下文初始化器ApplicationContextInitializer一樣(區(qū)別在于這里不再直接從spring.factories文件中獲取內(nèi)容,而是走cache(MultiValueMap<String, String>)緩存)。
4)推斷應(yīng)用引導(dǎo)類(lèi)
this.mainApplicationClass = deduceMainApplicationClass();
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
}
return null;
}該方法根據(jù)當(dāng)前線(xiàn)程執(zhí)行棧來(lái)判斷其棧中哪個(gè)類(lèi)包含main方法,然后將找到的類(lèi)名通過(guò)反射返回Class對(duì)象。
至此,在SpringApplication構(gòu)造過(guò)程中,SpringApplication屬性primarySources、webApplicationType、initializers、listeners 和 mainApplicationClass都被初始化了。
到此這篇關(guān)于SpringBoot啟動(dòng)之SpringApplication初始化詳解的文章就介紹到這了,更多相關(guān)SpringApplication初始化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Monaco?Editor實(shí)現(xiàn)sql和java代碼提示實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Monaco?Editor代碼提示sql和java實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
java實(shí)現(xiàn)系統(tǒng)多級(jí)文件夾復(fù)制
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)系統(tǒng)多級(jí)文件夾復(fù)制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
關(guān)于Spring不同類(lèi)型的注入方式 p-namespace,c-namespace
這篇文章主要介紹了Spring不同類(lèi)型的注入方式 p-namespace,c-namespace。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot項(xiàng)目整合druid數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)
這篇文章主要介紹了springboot項(xiàng)目整合druid數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringBoot實(shí)現(xiàn)埋點(diǎn)監(jiān)控
本文主要介紹了SpringBoot實(shí)現(xiàn)埋點(diǎn)監(jiān)控,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
java整數(shù)與byte數(shù)組的轉(zhuǎn)換實(shí)現(xiàn)代碼
這篇文章主要介紹了java整數(shù)與byte數(shù)組的轉(zhuǎn)換實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-07-07
解決SpringMVC接收不到ajaxPOST參數(shù)的問(wèn)題
今天小編就為大家分享一篇解決SpringMVC接收不到ajaxPOST參數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08

