SpringBoot啟動過程與自動配置過程解讀
一、Spring Boot 啟動流程
Spring Boot 應(yīng)用的入口是 main 方法中的 SpringApplication.run(),但這行代碼背后藏著一整套“初始化-配置-啟動”的流水線。
我們可以將其分為構(gòu)造階段和運行階段兩大步,每一步都有明確的職責(zé)邊界。
1.1 構(gòu)造階段:初始化核心組件
SpringApplication 實例的創(chuàng)建是啟動的第一步,這個階段的核心是“搭骨架”——確定應(yīng)用類型、加載初始化器和監(jiān)聽器,為后續(xù)運行鋪路。
- 驗證主類合法性:通過
Assert.notNull確保傳入的主配置類(標(biāo)注@SpringBootApplication的類)非空,這是整個應(yīng)用的“根”。 - 推斷應(yīng)用類型:通過
WebApplicationType.deduceFromClasspath()檢查類路徑中是否存在DispatcherServlet(MVC)或DispatcherHandler(WebFlux),自動判斷是SERVLET、REACTIVE還是非 Web 應(yīng)用(NONE)。 - 加載初始化器與監(jiān)聽器:從
META-INF/spring.factories中讀取ApplicationContextInitializer和ApplicationListener的實現(xiàn)類。這些組件是 Spring Boot 的“擴(kuò)展點”,例如初始化器可用于預(yù)先配置上下文,監(jiān)聽器可監(jiān)聽啟動各階段事件。 - 定位主程序類:通過棧追蹤找到調(diào)用
main方法的類,作為應(yīng)用的入口標(biāo)記。
關(guān)鍵源碼片段:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
1.2 運行階段:從環(huán)境準(zhǔn)備到容器啟動
SpringApplication.run() 方法是真正的“執(zhí)行引擎”,可細(xì)分為 10 個關(guān)鍵步驟,環(huán)環(huán)相扣:
- 啟動監(jiān)控與監(jiān)聽器:通過
StopWatch記錄啟動時間,同時觸發(fā)SpringApplicationRunListeners.starting(),通知所有監(jiān)聽器“應(yīng)用開始啟動”。 - 環(huán)境配置:創(chuàng)建
ConfigurableEnvironment(根據(jù)應(yīng)用類型選擇StandardServletEnvironment或StandardReactiveWebEnvironment),并加載系統(tǒng)變量、配置文件(如application.yml)等。完成后調(diào)用environmentPrepared事件,允許監(jiān)聽器對環(huán)境進(jìn)行二次調(diào)整。 - 打印 Banner:默認(rèn)打印 Spring Boot 版本信息,可通過
resources/banner.txt自定義(支持 ASCII 藝術(shù)或變量替換)。 - 創(chuàng)建應(yīng)用上下文:根據(jù)應(yīng)用類型生成對應(yīng)的 IOC 容器,例如 Servlet 應(yīng)用使用
AnnotationConfigServletWebServerApplicationContext。 - 上下文準(zhǔn)備:將環(huán)境、命令行參數(shù)等注入上下文,執(zhí)行初始化器的
initialize方法,并觸發(fā)contextPrepared事件。 - 上下文刷新:調(diào)用
refreshContext,觸發(fā) Spring 容器的核心流程(Bean 定義加載、實例化、依賴注入等),同時啟動嵌入式服務(wù)器(如 Tomcat)。 - 收尾工作:執(zhí)行
afterRefresh(預(yù)留擴(kuò)展點),停止計時器,并觸發(fā)started事件。 - 回調(diào)自定義邏輯:從容器中獲取
ApplicationRunner和CommandLineRunner的實現(xiàn)類,按順序執(zhí)行其run方法(適合啟動后初始化數(shù)據(jù)等操作)。 - 啟動完成:觸發(fā)
running事件,應(yīng)用正式就緒。 - 異常處理:若啟動失敗,調(diào)用
failed事件,打印異常并關(guān)閉上下文。
實戰(zhàn)技巧:若需在啟動后執(zhí)行初始化邏輯(如加載緩存),優(yōu)先使用 ApplicationRunner(支持 ApplicationArguments 解析)而非 CommandLineRunner(直接接收字符串?dāng)?shù)組)。
二、自動配置:Spring Boot 的“智能配置”核心
Spring Boot 最令人稱道的“自動配置”,本質(zhì)是“基于條件的約定配置”。
它通過一套規(guī)則判斷環(huán)境中存在的依賴,自動裝配對應(yīng)的組件,避免手動編寫 XML 或 @Bean 配置。
2.1 自動配置的底層原理
自動配置的觸發(fā)點是 @EnableAutoConfiguration 注解(被 @SpringBootApplication 間接包含),其核心邏輯在 AutoConfigurationImportSelector 中:
- 加載候選配置類:通過
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader),掃描所有 Jar 包的META-INF/spring.factories,獲取EnableAutoConfiguration對應(yīng)的配置類列表(如HttpEncodingAutoConfiguration、DataSourceAutoConfiguration等)。 - 過濾與去重:移除重復(fù)或被排除的配置類(通過
@SpringBootApplication(exclude = ...)指定),再通過條件注解(如@ConditionalOnClass)判斷配置類是否生效。 - 注入容器:將生效的配置類加載到容器中,其內(nèi)部的
@Bean方法會自動生成組件。
關(guān)鍵源碼片段:
// AutoConfigurationImportSelector 中加載候選配置類的邏輯
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories");
return configurations;
}
2.2 條件注解:自動配置的“開關(guān)”
自動配置的“智能”依賴于 @Conditional 系列注解,它們決定了一個配置類或 @Bean 方法是否生效。
常用條件注解如下:
| 注解 | 作用 | 示例場景 |
|---|---|---|
| @ConditionalOnClass | 類路徑存在指定類時生效 | 檢測到 DataSource.class 時配置數(shù)據(jù)源 |
| @ConditionalOnMissingBean | 容器中不存在指定 Bean 時生效 | 若用戶未定義 RestTemplate,則自動配置默認(rèn)實例 |
| @ConditionalOnProperty | 配置項滿足條件時生效 | 通過 spring.datasource.enabled=true 控制數(shù)據(jù)源是否啟用 |
| @ConditionalOnWebApplication | 僅 Web 應(yīng)用生效 | 配置 DispatcherServlet |
實戰(zhàn)案例:
HttpEncodingAutoConfiguration(HTTP 編碼自動配置)的條件判斷:
@Configuration
@EnableConfigurationProperties(HttpProperties.class) // 綁定配置文件屬性
@ConditionalOnWebApplication(type = Type.SERVLET) // 僅 Servlet 應(yīng)用生效
@ConditionalOnClass(CharacterEncodingFilter.class) // 存在字符編碼過濾器類時生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 若用戶未定義,則自動配置
public CharacterEncodingFilter characterEncodingFilter() {
// 從 HttpProperties 中讀取配置(如 spring.http.encoding.charset=utf-8)
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(properties.getCharset().name());
return filter;
}
}
技巧:
若需禁用某個自動配置(如默認(rèn)的數(shù)據(jù)源配置),可通過
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
或配置
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
2.3 自定義自動配置:擴(kuò)展 Spring Boot
若需為自己的組件實現(xiàn)自動配置(如公司內(nèi)部 SDK),需遵循以下步驟:
編寫配置類:使用 @Configuration 和條件注解定義組件裝配邏輯,通過 @EnableConfigurationProperties 綁定配置屬性。
注冊配置類:在 Jar 包的 META-INF/spring.factories 中添加:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.sdk.MyComponentAutoConfiguration
添加配置元數(shù)據(jù):在 META-INF/spring-configuration-metadata.json 中定義配置項的描述(IDE 會自動提示),例如:
{
"properties": [
{
"name": "example.sdk.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "是否啟用 SDK 組件"
}
]
}
驗證方法:啟動應(yīng)用時添加 --debug 參數(shù),控制臺會打印自動配置報告,顯示哪些配置類生效(Positive matches)或不生效(Negative matches)。
三、總結(jié):Spring Boot 便捷性的本質(zhì)
Spring Boot 的啟動流程和自動配置,本質(zhì)是“約定優(yōu)于配置”的極致體現(xiàn):
- 啟動流程通過標(biāo)準(zhǔn)化的步驟,將 Spring 容器的初始化與嵌入式服務(wù)器的啟動無縫銜接,減少手動干預(yù)。
- 自動配置基于條件注解和
spring.factories機(jī)制,實現(xiàn)了“依賴驅(qū)動配置”,讓開發(fā)者專注于業(yè)務(wù)邏輯而非框架整合。
理解這些原理后,不僅能更高效地排查問題(如啟動慢、自動配置失效),還能靈活擴(kuò)展 Spring Boot(如自定義 starters 或啟動流程)。
記住:Spring Boot 不是“魔法”,而是對 Spring 框架的“工程化封裝”——看透其源碼,就能真正掌控它。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java反射 PropertyDescriptor類案例詳解
這篇文章主要介紹了Java反射 PropertyDescriptor類案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
詳解在SpringBoot應(yīng)用中獲取應(yīng)用上下文方法
本篇文章主要介紹了詳解在SpringBoot應(yīng)用中獲取應(yīng)用上下文方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04
Java數(shù)據(jù)結(jié)構(gòu)二叉樹難點解析
樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點)按分支關(guān)系組織起來的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會的族譜和各種社會組織機(jī)構(gòu)都可用樹形象表示2021-10-10
SpringBoot如何整合Springsecurity實現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制
這篇文章主要給大家介紹了關(guān)于SpringBoot如何整合Springsecurity實現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制的相關(guān)資料,文中通過圖文以及實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-01-01
IDEA POM文件配置profile實現(xiàn)不同環(huán)境切換的方法步驟
這篇文章主要介紹了IDEA POM文件配置profile實現(xiàn)不同環(huán)境切換的方法步驟2024-03-03
Mybatis-plus如何提前獲取實體類用雪花算法生成的ID
本文主要介紹了Mybatis-plus如何提前獲取實體類用雪花算法生成的ID,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
基于Java實現(xiàn)PDF文本旋轉(zhuǎn)傾斜
這篇文章主要介紹了基于Java實現(xiàn)PDF文本旋轉(zhuǎn)傾斜,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-05-05

