一文徹底弄懂Spring Boot的啟動過程
一,Spring Boot啟動過程
1. 啟動入口
Spring Boot 應(yīng)用的啟動入口通常是一個包含 @SpringBootApplication 注解的主類,并調(diào)用 SpringApplication.run() 方法。@SpringBootApplication 是一個復(fù)合注解,包含了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan,從而開啟了自動配置和組件掃描。
源碼路徑在 SpringApplication 類的 run() 方法:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return new SpringApplication(primarySource).run(args);
}
這個入口主要做了以下幾件事情:
- 創(chuàng)建 SpringApplication 實例:初始化 Spring Boot 環(huán)境。
- 初始化環(huán)境和監(jiān)聽器:設(shè)置啟動的
Environment,并且添加ApplicationListener監(jiān)聽器。 - 準備和刷新 Spring 上下文:通過
prepareContext和refreshContext方法進行上下文環(huán)境的準備和刷新。
2. 創(chuàng)建 SpringApplication 實例
在 SpringApplication 的構(gòu)造方法中,Spring Boot 解析應(yīng)用的啟動模式(例如是 Web 應(yīng)用、Servlet 應(yīng)用或是普通應(yīng)用),并初始化應(yīng)用的上下文類型。Spring Boot 的不同上下文類型包括 AnnotationConfigApplicationContext(非 Web 應(yīng)用)和 AnnotationConfigServletWebServerApplicationContext(Web 應(yīng)用)。
3. 初始化 Environment 和監(jiān)聽器
接下來,Spring Boot 會初始化 ConfigurableEnvironment,這個環(huán)境中包含了系統(tǒng)的屬性、環(huán)境變量、配置文件等數(shù)據(jù),作為后續(xù)加載 Bean 定義和初始化的基礎(chǔ)。
同時,Spring Boot 也會初始化一系列的 ApplicationListener,用于監(jiān)聽和處理應(yīng)用啟動過程中的事件,比如 ApplicationEnvironmentPreparedEvent、ApplicationPreparedEvent 等。
4. 加載配置類并觸發(fā)自動配置
Spring Boot 使用 @EnableAutoConfiguration 注解觸發(fā)自動配置,核心實現(xiàn)是在 AutoConfigurationImportSelector 中加載 META-INF/spring.factories 配置文件,文件中列出了許多自動配置類(如 DataSourceAutoConfiguration、JpaRepositoriesAutoConfiguration 等),根據(jù)條件(例如某些 Bean 是否存在、某些屬性是否被配置等)加載相應(yīng)的自動配置。
5. 加載并注冊 Bean
在 refreshContext() 方法中,Spring Boot 調(diào)用 refresh() 方法,這一步驟中完成了 BeanFactory 的初始化和 BeanPostProcessor 的注冊,并解析 @Component、@Service、@Repository 等注解標注的 Bean 定義,將它們注冊到 BeanFactory 中。
在源碼層面,refresh() 方法中,invokeBeanFactoryPostProcessors 和 registerBeanPostProcessors 這兩個方法是關(guān)鍵,分別用于執(zhí)行所有 BeanFactoryPostProcessor 和 BeanPostProcessor,確保 Bean 的生命周期正確管理。
6. Web 環(huán)境中的嵌入式容器啟動
在 Web 應(yīng)用中,Spring Boot 會啟動嵌入式 Web 容器(如 Tomcat 或 Jetty)。Spring Boot 默認通過 ServletWebServerApplicationContext 啟動內(nèi)嵌的 Web 服務(wù)器。在 refresh() 的最后,會啟動嵌入式容器,將應(yīng)用作為 Web 應(yīng)用發(fā)布。
7. 執(zhí)行 ApplicationRunner 和 CommandLineRunner
Spring Boot 啟動完成后,會掃描并執(zhí)行所有實現(xiàn)了 ApplicationRunner 和 CommandLineRunner 接口的 Bean。它們可以用于在啟動后執(zhí)行自定義邏輯。
8. 發(fā)布應(yīng)用啟動完成事件
最后,Spring Boot 發(fā)布 ApplicationReadyEvent 事件,通知所有監(jiān)聽器應(yīng)用已啟動完成。至此,Spring Boot 應(yīng)用正式啟動完成,可以接收 HTTP 請求或執(zhí)行其他任務(wù)。
二、Spring Boot 啟動過程的架構(gòu)設(shè)計
在 Spring Boot 應(yīng)用啟動的過程中,SpringApplication.run() 是最常用的啟動方式。通過這個方法,Spring Boot 為開發(fā)者屏蔽了大量復(fù)雜的初始化細節(jié),我們只需提供主啟動類的入口和簡單的配置信息即可啟動整個應(yīng)用。
下面我們從源碼入手,分步驟分析 SpringApplication.run 進行的操作。
1,SpringApplication.run() 的詳細流程
SpringApplication.run 主要完成以下幾大步驟:
-
初始化 SpringApplication 實例:
該實例負責(zé)整個 Spring Boot 應(yīng)用的啟動過程,通過判斷應(yīng)用類型和設(shè)置環(huán)境變量為后續(xù)配置加載和應(yīng)用上下文創(chuàng)建提供基礎(chǔ)。核心方法為
SpringApplication#prepareEnvironment和SpringApplication#createApplicationContext。 -
創(chuàng)建應(yīng)用上下文并刷新上下文:
SpringApplication將根據(jù)應(yīng)用類型來創(chuàng)建不同的ApplicationContext(如AnnotationConfigApplicationContext或ServletWebServerApplicationContext),并將所有Bean裝載到上下文中。 -
加載環(huán)境配置:
Spring Boot 會基于開發(fā)環(huán)境或生產(chǎn)環(huán)境加載不同的配置文件。核心是
ConfigFileApplicationListener監(jiān)聽配置事件,解析應(yīng)用配置文件(application.properties或application.yml)并裝配到應(yīng)用上下文的Environment對象中。 -
啟動嵌入式容器:
如果是 Web 應(yīng)用,Spring Boot 會啟動內(nèi)嵌的服務(wù)器(如 Tomcat、Jetty 或 Undertow),并將
DispatcherServlet注冊到服務(wù)器中。
2,SpringApplication 核心設(shè)計類
在源碼層面,SpringApplication 是啟動過程中的關(guān)鍵類。它通過構(gòu)造函數(shù)和 run() 方法完成了以下工作:
public class SpringApplication {
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 = deduceWebApplicationType();
this.setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
this.setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
public ConfigurableApplicationContext run(String... args) {
// 初始化階段
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.started(context);
callRunners(context, applicationArguments);
} catch (Exception ex) {
handleRunFailure(context, listeners, ex);
throw new IllegalStateException(ex);
} finally {
stopWatch.stop();
}
return context;
}
}
源碼揭示了 SpringApplication 的核心功能在于配置監(jiān)聽器、加載環(huán)境、創(chuàng)建上下文等幾個方面。通過 deduceWebApplicationType() 方法判斷 Web 應(yīng)用類型,為接下來的 ApplicationContext 選擇提供了依據(jù)。這種設(shè)計實現(xiàn)了啟動流程的高度定制和靈活適應(yīng)性。
三、啟動過程中的關(guān)鍵組件及設(shè)計模式
Spring Boot 的啟動流程涉及到多個設(shè)計模式,這些模式不僅提升了代碼的可讀性和靈活性,也確保了在不同的業(yè)務(wù)場景下能夠快速地調(diào)整啟動行為。
1,ApplicationContext 和 ConfigurableEnvironment
ApplicationContext 是 Spring 框架的核心概念之一,提供了 IoC 容器的實現(xiàn)和應(yīng)用上下文的管理。在 Spring Boot 中,ApplicationContext 包含了所有的 Bean,并提供了應(yīng)用與外部環(huán)境的接口,如 ConfigurableEnvironment,用于管理應(yīng)用的環(huán)境配置和屬性。
ApplicationContext 的核心設(shè)計
ApplicationContext 是一個高度抽象的接口,它有多個具體實現(xiàn),如 AnnotationConfigApplicationContext 和 ServletWebServerApplicationContext。Spring Boot 的 SpringApplication 會根據(jù)應(yīng)用的類型選擇合適的 ApplicationContext 實現(xiàn),并對其進行配置和初始化:
- 非 Web 應(yīng)用:使用
AnnotationConfigApplicationContext加載配置類和 Bean。 - Web 應(yīng)用:使用
ServletWebServerApplicationContext,并加載嵌入式 Web 容器配置。
這種設(shè)計模式提升了 ApplicationContext 的適配性,使其可以靈活適應(yīng)各種不同類型的應(yīng)用。
ConfigurableEnvironment 環(huán)境配置的加載
ConfigurableEnvironment 提供了應(yīng)用的環(huán)境信息,包括系統(tǒng)屬性、環(huán)境變量以及外部化的配置文件內(nèi)容。在 Spring Boot 啟動過程中,ConfigurableEnvironment 會在 prepareEnvironment() 方法中被初始化。
在 ConfigurableEnvironment 中,屬性源的優(yōu)先級管理極大地提升了配置的靈活性。Spring Boot 根據(jù)不同的 PropertySource(如 application.properties、環(huán)境變量、命令行參數(shù)等),提供優(yōu)先級管理,這樣使得在復(fù)雜環(huán)境下也能靈活覆蓋配置。
2,ApplicationListener 事件驅(qū)動模型
ApplicationListener 是 Spring 框架中事件驅(qū)動機制的實現(xiàn),Spring Boot 使用該機制管理啟動過程中各類重要事件。以下是常見的啟動事件:
ApplicationStartingEvent:在SpringApplication.run()開始時觸發(fā)。ApplicationEnvironmentPreparedEvent:在Environment準備好之后觸發(fā)。ApplicationPreparedEvent:在上下文加載完成之前觸發(fā)。ApplicationStartedEvent:在上下文刷新完成之后觸發(fā)。ApplicationReadyEvent:應(yīng)用啟動完成時觸發(fā)。
事件驅(qū)動模型允許開發(fā)者在應(yīng)用啟動的各個階段進行自定義操作,極大增強了擴展性和靈活性。
3,依賴注入和條件配置加載機制
Spring Boot 中自動配置依賴于條件加載機制,核心在于 @Conditional 系列注解,比如 @ConditionalOnClass 和 @ConditionalOnMissingBean 等。這些注解允許 Spring Boot 根據(jù)實際情況有選擇性地加載配置:
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
// 數(shù)據(jù)源自動配置邏輯
}
這種條件注入模式通過按需加載 Bean,有效減少了資源的浪費。此設(shè)計模式也讓 Spring Boot 能夠快速適應(yīng)不同的環(huán)境和依賴場景,避免不必要的 Bean 被加載。
四、自動配置的實現(xiàn)機制
Spring Boot 通過 @EnableAutoConfiguration 啟動自動配置功能,它的底層實現(xiàn)機制是 AutoConfigurationImportSelector 和 SpringFactoriesLoader,其中 SpringFactoriesLoader 會掃描 META-INF/spring.factories 文件加載自動配置類。
1,SpringFactoriesLoader 詳解
Spring Boot 自動配置的一個核心機制是 SpringFactoriesLoader,它會從 META-INF/spring.factories 文件中加載所有需要自動配置的類。這種文件配置的方式讓 Spring Boot 能夠輕松拓展新的自動配置功能。
@EnableAutoConfiguration 通過 AutoConfigurationImportSelector 來加載自動配置類,自動配置的實現(xiàn)類和邏輯則由 @Conditional 注解管理,這樣使得自動配置具有按需加載的特性。
2,條件注解與場景應(yīng)用
自動配置機制在實際業(yè)務(wù)中應(yīng)用非常廣泛。舉例來說,Spring Boot 中數(shù)據(jù)源的配置是通過 DataSourceAutoConfiguration 類實現(xiàn)的。在 DataSourceAutoConfiguration 中,使用 @ConditionalOnClass 注解來判斷類路徑中是否存在 DataSource 類,若存在,則注入數(shù)據(jù)源配置。
這類場景非常適合用在多數(shù)據(jù)源配置上,開發(fā)者可以利用條件注解在生產(chǎn)環(huán)境下配置多個數(shù)據(jù)庫源,而在測試環(huán)境中只加載測試數(shù)據(jù)源配置。
五、嵌入式容器的啟動流程
Spring Boot 在 Web 應(yīng)用中默認使用嵌入式容器,這樣可以使應(yīng)用獨立于外部服務(wù)器而運行,提升了應(yīng)用的獨立性和便捷性。
1,嵌入式容器的啟動設(shè)計
在 Spring Boot 啟動 Web 應(yīng)用時,會根據(jù) ServletWebServerApplicationContext 加載嵌入式容器。以下是啟動嵌入式容器的關(guān)鍵流程:
- 創(chuàng)建 ServletWebServerApplicationContext:Spring Boot 會選擇 Web 應(yīng)用的上下文類
ServletWebServerApplicationContext,并加載WebServerFactory工廠類。 - 創(chuàng)建 Web 服務(wù)器:Spring Boot 使用工廠類創(chuàng)建內(nèi)嵌的 Web 服務(wù)器,如 Tomcat、Jetty 或 Undertow。
- 注冊 DispatcherServlet:Spring Boot 將
DispatcherServlet注冊到內(nèi)嵌服務(wù)器中,并通過ServletRegistrationBean對其進行初始化和配置。
這種設(shè)計模式使得 Spring Boot 應(yīng)用無縫支持不同類型的 Web 容器,并根據(jù)環(huán)境靈活選擇合適的容器。
2,嵌入式容器在多環(huán)境中的應(yīng)用
嵌入式容器尤其適合微服務(wù)架構(gòu),它能在容器化場景中快速適應(yīng) Docker 或 Kubernetes 等部署平臺。此外,Spring Boot 允許開發(fā)者通過簡單配置切換不同類型的 Web 服務(wù)器(如 Tomcat 到 Jetty),這樣的設(shè)計為企業(yè)級應(yīng)用提供了高靈活性。

浙公網(wǎng)安備 33010602011771號