Java?SpringBoot核心源碼詳解
SpringBoot源碼主線分析
我們要分析一個框架的源碼不可能通過一篇文章就搞定的,本文我們就來分析下SpringBoot源碼中的主線流程。先掌握SpringBoot項目啟動的核心操作,然后我們再深入每一個具體的實現(xiàn)細節(jié),注:本系列源碼都以SpringBoot2.2.5.RELEASE版本來講解
1.SpringBoot啟動的入口
當我們啟動一個SpringBoot項目的時候,入口程序就是main方法,而在main方法中就執(zhí)行了一個run方法。
@SpringBootApplication public class StartApp { public static void main(String[] args) { SpringApplication.run(StartApp.class); } }
2.run方法
然后我們進入run()方法中看。代碼比較簡單
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { // 調用重載的run方法,將傳遞的Class對象封裝為了一個數(shù)組 return run(new Class<?>[] { primarySource }, args); }
調用了重載的一個run()方法,將我們傳遞進來的類對象封裝為了一個數(shù)組,僅此而已。我們再進入run()方法。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { // 創(chuàng)建了一個SpringApplication對象,并調用其run方法 // 1.先看下構造方法中的邏輯 // 2.然后再看run方法的邏輯 return new SpringApplication(primarySources).run(args); }
在該方法中創(chuàng)建了一個SpringApplication對象。同時調用了SpringApplication對象的run方法。這里的邏輯有分支,先看下SpringApplication的構造方法中的邏輯
3.SpringApplication構造器
我們進入SpringApplication的構造方法,看的核心代碼為
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 傳遞的resourceLoader為null this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 記錄主方法的配置類名稱 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 記錄當前項目的類型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 加載配置在spring.factories文件中的ApplicationContextInitializer對應的類型并實例化 // 并將加載的數(shù)據(jù)存儲在了 initializers 成員變量中。 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 初始化監(jiān)聽器 并將加載的監(jiān)聽器實例對象存儲在了listeners成員變量中 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 反推main方法所在的Class對象 并記錄在了mainApplicationClass對象中 this.mainApplicationClass = deduceMainApplicationClass(); }
在本方法中完成了幾個核心操作
1.推斷當前項目的類型
2.加載配置在spring.factories
文件中的ApplicationContextInitializer
中的類型并實例化后存儲在了initializers中。
3.和2的步驟差不多,完成監(jiān)聽器的初始化操作,并將實例化的監(jiān)聽器對象存儲在了listeners成員變量中
4.通過StackTrace反推main方法所在的Class對象
上面的核心操作具體的實現(xiàn)細節(jié)我們在后面的詳細文章會給大家剖析
4.run方法
接下來我們在回到SpringApplication.run()方法中。
public ConfigurableApplicationContext run(String... args) { // 創(chuàng)建一個任務執(zhí)行觀察器 StopWatch stopWatch = new StopWatch(); // 開始執(zhí)行記錄執(zhí)行時間 stopWatch.start(); // 聲明 ConfigurableApplicationContext 對象 ConfigurableApplicationContext context = null; // 聲明集合容器用來存儲 SpringBootExceptionReporter 啟動錯誤的回調接口 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 設置了一個名為java.awt.headless的系統(tǒng)屬性 // 其實是想設置該應用程序,即使沒有檢測到顯示器,也允許其啟動. //對于服務器來說,是不需要顯示器的,所以要這樣設置. configureHeadlessProperty(); // 獲取 SpringApplicationRunListener 加載的是 EventPublishingRunListener // 獲取啟動時到監(jiān)聽器 SpringApplicationRunListeners listeners = getRunListeners(args); // 觸發(fā)啟動事件 listeners.starting(); try { // 構造一個應用程序的參數(shù)持有類 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 創(chuàng)建并配置環(huán)境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 配置需要忽略的BeanInfo信息 configureIgnoreBeanInfo(environment); // 輸出的Banner信息 Banner printedBanner = printBanner(environment); // 創(chuàng)建應用上下文對象 context = createApplicationContext(); // 加載配置的啟動異常處理器 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 刷新前操作 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新應用上下文 完成Spring容器的初始化 refreshContext(context); // 刷新后操作 afterRefresh(context, applicationArguments); // 結束記錄啟動時間 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 事件廣播 啟動完成了 listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { // 事件廣播啟動出錯了 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // 監(jiān)聽器運行中 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } // 返回上下文對象--> Spring容器對象 return context; }
在這個方法中完成了SpringBoot項目啟動的很多核心的操作,我們來總結下上面的步驟
- 創(chuàng)建了一個任務執(zhí)行的觀察器,統(tǒng)計啟動的時間
- 聲明
ConfigurableApplicationContext
對象 - 聲明集合容器來存儲
SpringBootExceptionReporter
即啟動錯誤的回調接口 - 設置
java.awt.headless
的系統(tǒng)屬性 - 獲取我們之間初始化的監(jiān)聽器(
EventPublishingRunListener
),并觸發(fā)starting事件 - 創(chuàng)建
ApplicationArguments
這是一個應用程序的參數(shù)持有類 - 創(chuàng)建
ConfigurableEnvironment
這時一個配置環(huán)境的對象 - 配置需要忽略的
BeanInfo
信息 - 配置Banner信息對象
- 創(chuàng)建對象的上下文對象
- 加載配置的啟動異常的回調異常處理器
- 刷新應用上下文,本質就是完成Spring容器的初始化操作
- 啟動結束記錄啟動耗時
- 完成對應的事件廣播
- 返回應用上下文對象。
到此SpringBoot項目的啟動初始化的代碼的主要流程就介紹完成了。細節(jié)部分后面詳細講解。
總結
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
SpringCloud Eureka 服務注冊實現(xiàn)過程
這篇文章主要介紹了SpringCloud Eureka 服務注冊實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-10-10Spring Cloud Feign接口返回流的實現(xiàn)
這篇文章主要介紹了Spring Cloud Feign接口返回流的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-10-10HttpMessageConverter報文信息轉換器的深入講解
在Spring中內置了大量的HttpMessageConverter,通過請求頭信息中的MIME類型,選擇相應的HttpMessageConverter,這篇文章主要給大家介紹了關于HttpMessageConverter報文信息轉換器的相關資料,需要的朋友可以參考下2022-01-01