Spring Boot 啟動過程與自動配置詳解:從源碼到實現
在使用 Spring Boot 時,開發者常常會感到驚訝:為什么這么少的配置卻能實現如此豐富的功能?為何啟動一個 Spring Boot 應用可以變得如此簡單便捷?在這個看似平凡的啟動過程中,其實隱藏著一套精妙的自動化機制和源碼邏輯。本文將帶你深入探索 Spring Boot 的啟動流程,逐步揭開自動配置的幕后奧秘。通過了解這些底層原理,你將發現,原來每一次應用的無縫啟動都是精心設計的結果,讓你對 Spring Boot 有更深刻的理解和掌控力!
一、整體概述
(一)基本整體初步分析
Spring Boot 是一個用于構建獨立的、生產級的 Spring 應用程序的框架,它提供了自動化的配置和約定優于配置的原則。在理解 Spring Boot 的啟動配置原理之前,我們需要了解幾個關鍵概念。
首先,Spring Boot 使用了基于約定的自動配置機制。它通過在 classpath 下查找特定的配置文件和類,根據應用程序所使用的依賴自動配置 Spring 應用程序的各種組件。這樣可以大大簡化開發者的工作,減少了手動配置的需求。
其次,Spring Boot 使用了條件化配置(Conditional Configuration)的機制。這意味著配置的應用取決于一組條件是否滿足。條件可以基于多種因素,如 classpath 中存在特定的類、特定的 bean 是否存在等等。通過條件化配置,Spring Boot 可以根據不同的環境和需求進行動態的配置。
Spring Boot 的啟動配置原理可以概括如下:
- 在啟動過程中,Spring Boot 會加載并解析應用程序的配置文件,其中包括 application.properties 或 application.yml 文件等。這些文件中可以定義各種屬性和配置信息,如數據庫連接、日志級別等。
- Spring Boot 會自動掃描 classpath 下的特定包,尋找帶有特定注解的類,如 @SpringBootApplication。這個注解標識了一個 Spring Boot 應用程序的入口點。
- 根據配置文件中的屬性和條件化配置的機制,Spring Boot 自動配置應用程序的各種組件,包括數據庫連接池、消息隊列、Web 服務器等。如果需要進行自定義配置,可以使用專門的注解或編寫自定義的配置類。
- 在應用程序啟動時,Spring Boot 會初始化 Spring 容器,并根據配置進行相應的初始化工作。這包括創建和管理 bean、處理依賴注入等。
總的來說,Spring Boot 的啟動配置原理是基于自動化的約定和條件化配置機制。它通過讀取配置文件、掃描注解、自動配置組件等步驟,簡化了應用程序的配置過程,并提供了靈活性和易用性。
(二)從啟動來看整體過程圖分析
每個SpringBoot程序都有一個主入口main方法,main里面調用SpringApplication.run()啟動整個SpringBoot程序,該方法所在類需要使用@SpringBootApplication注解,例如如下
-
package org.zyf.javabasic;
-
-
import org.springframework.boot.SpringApplication;
-
import org.springframework.boot.autoconfigure.SpringBootApplication;
-
import org.springframework.context.ApplicationContext;
-
import org.springframework.context.annotation.ComponentScan;
-
import org.springframework.context.annotation.EnableAspectJAutoProxy;
-
import springfox.documentation.swagger2.annotations.EnableSwagger2;
-
-
/**
-
* 描述:啟動入口類
-
*
-
* @author yanfengzhang
-
* @date 2019-12-19 18:11
-
*/
-
-
-
-
-
public class ZYFApplication {
-
public static void main(String[] args) {
-
ApplicationContext context = SpringApplication.run(ZYFApplication.class, args);
-
}
其中對@SpringBootApplication進行展開分析:
-
//
-
// Source code recreated from a .class file by IntelliJ IDEA
-
// (powered by FernFlower decompiler)
-
//
-
-
package org.springframework.boot.autoconfigure;
-
-
import java.lang.annotation.Documented;
-
import java.lang.annotation.ElementType;
-
import java.lang.annotation.Inherited;
-
import java.lang.annotation.Retention;
-
import java.lang.annotation.RetentionPolicy;
-
import java.lang.annotation.Target;
-
import org.springframework.boot.SpringBootConfiguration;
-
import org.springframework.boot.context.TypeExcludeFilter;
-
import org.springframework.context.annotation.ComponentScan;
-
import org.springframework.context.annotation.FilterType;
-
import org.springframework.context.annotation.ComponentScan.Filter;
-
import org.springframework.core.annotation.AliasFor;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
public SpringBootApplication {
-
-
-
-
Class<?>[] exclude() default {};
-
-
-
-
-
String[] excludeName() default {};
-
-
-
-
-
-
String[] scanBasePackages() default {};
-
-
-
-
-
-
Class<?>[] scanBasePackageClasses() default {};
-
}
@SpringBootApplication包括三個注解,功能如下:
- @SpringBootConfiguration(內部為@Configuration):被標注的類等于在spring的XML配置文件中(applicationContext.xml),裝配所有bean事務,提供了一個spring的上下文環境
- @ComponentScan:組件掃描,可自動發現和裝配Bean(比如@Component和@Configuration),默認掃描SpringApplication的run方法里類所在的包路徑下所有文件
- @EnableAutoConfiguration:激活SpringBoot自動裝配的特性
現在對主入口main方法進行展開來給出整體的流程圖分析

二、SpringApplication構造過程分析
進入main里面的run方法,創建了一個SpringApplication實例,配置一些基本的環境變量、資源、構造器、監聽器,進入這個SpringApplication有參構造函數
-
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
-
this.sources = new LinkedHashSet();
-
this.bannerMode = Mode.CONSOLE;
-
this.logStartupInfo = true;
-
this.addCommandLineProperties = true;
-
this.addConversionService = true;
-
this.headless = true;
-
this.registerShutdownHook = true;
-
this.additionalProfiles = new HashSet();
-
this.isCustomEnvironment = false;
-
this.resourceLoader = resourceLoader;
-
Assert.notNull(primarySources, "PrimarySources must not be null");
-
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
-
this.webApplicationType = WebApplicationType.deduceFromClasspath();
-
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
-
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
-
this.mainApplicationClass = this.deduceMainApplicationClass();
-
}
注意:在該構造方法內,做的工作就是把相關的類(主要是initializer和listener)加載進容器中,并沒有執行
(一)驗證主配置類不為空并且保存主類

(二)推斷項目的類型

進入對應方法分析如下:

推斷項目的類型可能為reactive、none、servlet三種類型,默認為servlet類型。其使用類加載器判斷類型的邏輯如下
|
類型 |
判斷情況 |
|---|---|
|
reactive |
存在Spring WebFlux的DispatcherHandler存在,但是Spring MVC的DispatcherServlet不存在 |
|
none |
二者都不存在 |
|
servlet |
剩余所有情況 |
(三)初始化initializers

先進入ApplicationContextInitializer接口,這個接口只有一個方法initialize
-
package org.springframework.context;
-
-
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
-
void initialize(C var1);
-
}
查看實現了該這個接口的類進行分析

以SharedMetadataReaderFactoryContextInitializer實現類為例,跳轉對應jar包,可以看到里面 spring.factories就在key為ApplicationContextInitializer中指定了對應的實現類,例如:

進入SharedMetadataReaderFactoryContextInitializer,其實現了ApplicationContextInitializer接口,并實現了里面的initialize方法

現在回到一開始再來看getSpringFactoriesInstance()方法,其核心為loadFactoryNames()方法

進入loadFactoryNames()方法,可以看到ApplicationContextInitializer的相關獲取內容直接就是從文件“META-INF/spring.factories”中獲取保存的

(四)加載相關的listeners

先進入ApplicationListener接口,這個接口只有一個方法onApplicationEvent
-
package org.springframework.context;
-
-
import java.util.EventListener;
-
-
-
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
-
void onApplicationEvent(E var1);
-
}
查看實現了該這個接口的類進行分析

以BackgroundPreinitializer實現類為例,跳轉對應jar包,可以看到里面 spring.factories就在key為ApplicationListener中指定了對應的實現類:

進入BackgroundPreinitializer,其實現了ApplicationListener,并實現了里面的onApplicationEvent
方法如下:

現在回到一開始再來看getSpringFactoriesInstance()方法,其處理流程和上面的一樣,即依然是從類路徑下找到META-INF/spring.factories配置的所有ApplicationListener
(五)決定ApplicationClass主程序

進入deduceMainApplicationClass方法

三、SpringApplication啟動過程分析

SpringBoot啟動方案,包括啟動流程的監聽模塊、加載配置環境模塊、及核心的創建上下文環境模塊以及后續的收尾回調等內容
(一)監控器監聽容器啟動并進行圖形化頁面處理

(二)監聽器SpringApplicationRunListeners開啟監聽

直接開始分析ApringApplicationRunListeners,內含SpringApplicationRunListener的集合,其中starting方法就是對listeners進行遍歷,對每個listener都調用starting方法

SpringApplicationRunListener和ApplicationListener都是SpringBoot中的事件監聽器,但是它們所監聽的事件和觸發時機有所不同,其區別如下:
- 監聽的事件不同
SpringApplicationRunListener主要監聽SpringApplication運行時的各種事件,例如應用程序開始啟動、應用程序啟動失敗、應用程序啟動完成等事件。而ApplicationListener主要監聽Spring容器中的各種事件,例如Bean加載完成、上下文刷新完成等事件。 - 觸發時機不同
SpringApplicationRunListener在SpringApplication啟動時就開始工作,可以接收到應用程序開始啟動、應用程序啟動失敗、應用程序啟動成功等各種事件。而ApplicationListener則是在Spring容器啟動完成后,才能開始工作,監聽的是Spring容器中的各種事件。 - 使用場景不同
在實際應用中,SpringApplicationRunListener主要用于監聽SpringApplication的啟動過程,例如在應用程序啟動前后執行某些操作、監聽應用程序啟動失敗事件并做出相應的操作等。而ApplicationListener則用于監聽Spring容器中的各種事件,例如在Bean加載完成后做出相應的操作、在上下文刷新完成后更新一些狀態等。
總之,盡管SpringApplicationRunListener和ApplicationListener都是SpringBoot中的事件監聽器,但是它們所監聽的事件、觸發時機、使用場景等都有所不同,我們需要根據具體的應用需求,選擇合適的監聽器來完成應用程序的事件處理。
在進入看一下SpringApplicationRunListener這個類
-
package org.springframework.boot;
-
-
import org.springframework.context.ConfigurableApplicationContext;
-
import org.springframework.core.env.ConfigurableEnvironment;
-
-
public interface SpringApplicationRunListener {
-
void starting();
-
-
void environmentPrepared(ConfigurableEnvironment environment);
-
-
void contextPrepared(ConfigurableApplicationContext context);
-
-
void contextLoaded(ConfigurableApplicationContext context);
-
-
void started(ConfigurableApplicationContext context);
-
-
void running(ConfigurableApplicationContext context);
-
-
void failed(ConfigurableApplicationContext context, Throwable exception);
-
}
對應方法說明如下
|
監聽方法 |
運行階段說明 |
SpringBoot起始版本 |
|---|---|---|
|
contextLoaded(ConfigurationApplicationEnvironment) |
ConfigurableApplicationContext完成加載,但仍未啟動;通知監聽器,ApplicationContext已經完成IoC配置 |
1.0 |
|
contextPrepared(ConfigurationApplicationEnvironment) |
ConfigurableApplicationContext準備妥當:通知監聽器,ApplicationContext已經創建并初始化完成 |
1.0 |
|
environmentPrepared(ConfigurationEnvironment) |
ConfigurationEnvironment準備妥當,允許將其調整 |
1.0 |
|
failed(ConfigurationApplicationEnvironment,Throwable) |
Spring應用運行失敗 |
2.0 |
|
running(ConfigurationApplicationEnvironment) |
Spring應用正在運行 |
2.0 |
|
started(ConfigurationApplicationEnvironment) |
ConfigurableApplicationContext已啟動,此時SpringBean已初始化完成 |
2.0 |
|
starting() |
run方法執行的時候立馬執行:通知監聽器,SpringBoot開始執行 |
1.0 |
總的來說就是創建了應用的監聽器SpringApplicationRunListeners并調用start()開始監聽,先在getRunListeners中獲取了所有的監聽器,然后starting開啟
(三)environmentPrepared環境準備處理

分析這段代碼,進入準備環境的方法prepareEnvironment中,可以看到如下:

首先創建了一個環境ConfigurationEnvironment(有的話就獲取,沒有則創建)

回到該方法返回的地方,通過this.configureEnvironment對環境進行設置,接著如下:

環境配置好以后回調了SpringApplicationRunListener的environmentPrepared函數,進入該方法:

可以看到environmentPrepared環境準備中進行了通知監聽器,Environment準備完成。
回到開始處,可以看到環境準備完成后通過bindToSpringApplication將環境綁定到程序中。
(四)banner打印

打印對應的banner信息

也就是啟動后的改部分,見如下

實際中,改圖可以進行替換,只需要在resources增加banner.txt信息即可,例如如下:

其中的原理可以繼續點開對應后續代碼分析,這個后續中講解替換思路。
(五)創建Spring應用上下文

創建應用上下文即IOC過程,IOC容器是驅動整體SpringBoot應用組件的核心,進入該方法:

這里的創建是根據SpringApplication在構造階段所推斷的web應用類型進行IOC容器的創建,IOC容器就是run返回的內容。
(六)Spring應用上下文準備階段

prepareContext方法將listeners、environment、applicationArguments、banner等重要組件與上下文對象關聯,對上下文對象進行進一步配置,進入該方法具體分析:

可以看到首先分別保存了剛才生成的environment、ApplicationContext,接下來的applyInitializers方法是執行初始化,進入該方法

方法內部遍歷所有的initializer,然后依次回調里面所有的initialize方法(這些initializer就是在springboot剛啟動時構造new springApplication時添加的),設置完當前環境并完成初始化之后,回調了所有Linsteners的contextPrepared方法

接下來將命令行參數和banner注冊到IOC容器來,如下:

最后全部操作都完成后,這個方法回調了Listeners的contextLoaded方法,如上。
(七)Spring應用上下文刷新階段

在該方法中首先注冊了一個shutdownHook線程,用來實現SpringBean銷毀生命周期回調

在執行完refresh之后的控制臺,可以看到tomcat和一些IOC容器的bean都被加載進去了

(八)Spring應用上下文收尾階段

其中afrerRefresh()并無內容處理,后續的版本中已經沒有改方法了
-
protected void afterRefresh(ConfigurableApplicationContext context,
-
ApplicationArguments args) {
-
}
收尾計時器停止,同時調用監聽器的started()。
(九)回調工作處理

進入該方法分析

ApplicationContext就是IOC容器,這個方法從IOC容器中獲取了所有的ApplicationRunner和ConmmandLineRunner,接下來進行遍歷和回調。
在callRunners使用的這兩個類幾乎可以等價,都是用于做一些客戶自定義的工作,而且是整個流程完成之后才會調用用戶自己定義的實現類的run方法,這兩個run方法的實現方法都是在容器基本初始化好的時候調用的。
緊接著,如果無異常代碼執行如下:

監聽器回調running()方法代表SpringApplication正常啟動結束。
(十)SpringApplication啟動異常處理

發生異常主要是對異常的處理,我們進入該方法分析

可以看到這個異常報告類也是支持自定義并且自動配置的,配置結束后,Springboot做了一些基本的收尾工作,返回了應用環境上下文(IOC容器)。
四、SpringBoot自動配置分析
Spring Boot 的自動化配置模塊是該框架的核心功能之一,它可以大大簡化應用程序的配置工作。下面是對 Spring Boot 自動化配置模塊的講解和分析:
- 自動化配置的原理:Spring Boot 的自動化配置模塊基于約定優于配置的原則。它通過在 classpath 下掃描依賴和配置,自動配置應用程序的各個組件。它使用條件化配置的機制,根據環境和條件自動選擇適當的配置。
- 自動配置的實現方式:Spring Boot 自動化配置模塊使用了 @Conditional 注解和條件注解來實現條件化配置。這些注解可以根據一組條件來決定是否啟用某個配置。例如,@ConditionalOnClass 根據 classpath 中是否存在指定的類來判斷是否啟用配置。
- 自動配置的加載順序:Spring Boot 的自動配置是通過在 classpath 下的 META-INF/spring.factories 文件中定義的自動配置類來實現的。這些自動配置類會被自動加載,并根據條件進行初始化和配置。根據條件的不同,可以有多個自動配置類被加載,它們會按照優先級順序進行配置。
- 自動配置的自定義:Spring Boot 允許開發者對自動配置進行自定義。你可以使用 @Conditional 注解和條件注解來定義自定義的條件,從而影響自動配置的行為。你還可以使用 @EnableAutoConfiguration 注解來控制自動配置的啟用或禁用。
- 自動配置的好處:Spring Boot 的自動化配置模塊帶來了很多好處。它大大減少了手動配置的工作量,提高了開發效率。它提供了合理的默認配置,減少了錯誤配置的風險。同時,它的條件化配置機制使得應用程序更具靈活性,能夠根據不同的環境和需求進行動態的配置。
總的來說,Spring Boot 的自動化配置模塊是該框架的重要特性之一。它通過約定優于配置的原則和條件化配置機制,實現了自動加載和配置應用程序的各個組件。這為開發者提供了便利和靈活性,并大大簡化了應用程序的配置過程。
現在回到我們一開始的圖示分析,該配置模塊的主要使用到了SpringFactoriesLoader,即Spring工廠加載器,該對象提供了loadFactoryNames方法,入參為factoryClass和classLoader,即需要傳入工廠類名稱和對應的類加載器,方法會根據指定的classLoader,加載該類加器搜索路徑下的指定文件,即spring.factories文件,傳入的工廠類為接口,獲取到這些實現類的類名后,loadFactoryNames方法返回類名集合,方法調用方得到這些集合后,再通過反射獲取這些類的類對象、構造方法,最終生成實例。
(一)自動裝配原理分析
從@SpringBootApplication中的@EnableAutoConfiguration注解中可以看到其import了一個自動配置導入選擇器AutoConfigurationImportSelect
-
package org.springframework.boot.autoconfigure;
-
-
import java.lang.annotation.Documented;
-
import java.lang.annotation.ElementType;
-
import java.lang.annotation.Inherited;
-
import java.lang.annotation.Retention;
-
import java.lang.annotation.RetentionPolicy;
-
import java.lang.annotation.Target;
-
import org.springframework.context.annotation.Import;
-
-
-
-
-
-
-
-
public EnableAutoConfiguration {
-
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
-
-
Class<?>[] exclude() default {};
-
-
String[] excludeName() default {};
-
}
其類圖如下

可以發現其最終實現了ImportSelector(選擇器)和BeanClassLoaderAware(bean類加載器中間件),其中這個選擇器的作用就是導入組件。
所有自動裝配的邏輯都是在AutoConfigurationImportSelector里面的selectImports方法中實現的

進入getAutoConfigurationEntry()方法

進入getCandidateConfigurations()獲取候選配置方法,可以看到核心的SpringFactoriesLoader的loadFactoryNames()方法

其中SpringFactoriesLoader是Spring Framework工廠機制的加載器,loadFactoryNames是其對應的加載方法,進入這個核心的loadFactoryNames方法中查看

該處加載原理如下:
- 掃描所有jar包路徑下 META-INF/spring.factories,這里是通過類加載器生成對應的url路徑
- 把掃描到的內容包裝成properties對象,并對這個對象的內容進行遍歷,返回map,map的key為接口的全類名,value為接口全部實現類列表(列表里元素去重,防止重復加載),這個value的信息后續會作為loadSpringFactories方法的返回值
- 在上一步返回的map之中查找并返回指定類名映射的實現類全類名列表
再看剛才getCandidateConfiguration方法中的getSpringFactoriesLoaderFactoryClass方法,返回的就是EnableAutoConfiguration類

也就是說要從剛才properties中再獲取這個類對應的值,把它們加到容器中。
選取mybatis-spring-boot-autoconfigure下的spring.factories文件分析一下:

每一個 xxxAutoConfiguration類都是容器中的一個組件,都加入到容器中,用它們做自動配置;
只有進入到容器中,這些自動配置類才會起作用——進行自動配置功能
(二)條件化自動裝配
對于使用@Configuration的自動配置類,其條件自動化裝配以@condition為核心。在spring底層中的@conditional注解會根據不同的滿足條件生效整個配置類里面的配置。
條件化裝配可以分為以下幾類:
Class條件注解
|
注解 |
說明 |
|---|---|
|
@ConditionalOnClass |
指定類存在時生效 |
|
@ConditionalOnMissingClass |
指定類缺失時生效 |
Bean條件注解
|
注解 |
說明 |
|---|---|
|
@ConditionalOnBean |
指定Bean存在時生效 |
|
@ConditionalOnMissingBean |
指定Bean缺失時生效 |
屬性條件注解
|
注解 |
說明 |
|---|---|
|
@ConditionalOnProperty |
使用屬性(application.properties)的值判斷是否生效 |
Web應用條件注解
|
注解 |
說明 |
|---|---|
|
@ConditionalOnWebApplication |
是web類型時生效 |
|
@ConditionalOnNotWebApplication |
不是web類型時生效 |
其他條件注解
|
@Conditional擴展注解 |
作用(判斷是否滿足當前指定條件) |
|---|---|
|
@ConditionalOnJava |
系統的java版本是否符合要求 |
|
@ConditionalOnExpression |
滿足SpEL表達式指定 |
|
@ConditionalOnSingleCandidate |
容器中只有一個指定的Bean,或者這個Bean是首選Bean |
|
@ConditionalOnResource |
類路徑下是否存在指定資源文件 |
|
@ConditionalOnJndi |
JNDI存在指定項 |
分析@ConditionalOnWebApplication
-
package org.springframework.boot.autoconfigure.condition;
-
-
import java.lang.annotation.Documented;
-
import java.lang.annotation.ElementType;
-
import java.lang.annotation.Retention;
-
import java.lang.annotation.RetentionPolicy;
-
import java.lang.annotation.Target;
-
import org.springframework.context.annotation.Conditional;
-
-
-
-
-
-
public ConditionalOnWebApplication {
-
ConditionalOnWebApplication.Type type() default ConditionalOnWebApplication.Type.ANY;
-
-
public static enum Type {
-
ANY,
-
SERVLET,
-
REACTIVE;
-
-
private Type() {
-
}
-
}
-
}
進入OnWebApplicationCondition類,里面有一個getMatchOutcome()方法,就是判斷是否符合當前配置條件

該方法首先判斷是否使用了這個注釋,然后使用isWebApplication來判斷當前是否是web應用,這些match的方法判斷指定的條件成立,才會給容器添加組件,配置內容才會生效。
(三)自動配置原理舉例:HttpEncodingAutoConfiguration(HTTP編碼自動配置)
可以看到以下信息:
- @Configuration 代表這是一個配置類,類似編寫的配置文件,也可以給容器中添加組件。
- @EnableConfigurationProperties 啟用指定類的ConfigurationProperties功能,將配置文件application.properties的值和ServerProperties綁定起來,并把ServerProperties加入到IOC容器中。
- @ConditionalOnClass用來判斷當前項目是否含有這個類,這里CharacterEncodingFilter的作用就是springMVC亂碼解決的過濾器(以前在spring的xml文件中配置的),如果有這個過濾器則配置生效。
- @ConditionalOnProperty判斷這個配置是否存在,matchIfMissing = true代表即使配置文件中不存在這個屬性也是默認生效的。
需要注意的是,在spring.factories中的自動配置類不是都能生效的,都有各自的生效條件。根據當前不同條件判斷,來決定這個配置類是否生效;一旦配置類生效,這個配置類就會給容器添加各種組件,這些組件的屬性從對應的properties中獲取,這些類里面的每一個屬性又是和配置文件綁定的。
五、總結
Spring Boot 的自動化配置和啟動流程為開發者提供了簡化的開發體驗,降低了配置和啟動的復雜性。通過深入理解 SpringApplication 的啟動步驟、自動配置的原理以及 Spring Boot 如何無縫集成各類組件,我們不僅能更好地運用 Spring Boot,還能更靈活地定制和優化應用。自動配置是 Spring Boot 的核心之一,它通過精巧的條件判斷實現了“按需配置”,確保應用在減少冗余的前提下獲得所需的功能支持。
在實際開發中,理解這些原理可以幫助我們在遇到問題時更快找到原因,尤其是當我們需要進行調優或者定制配置時,更能從容應對。希望通過本文的分析,你能夠更全面地掌握 Spring Boot 的核心機制,并在實際項目中充分發揮它的優勢。

浙公網安備 33010602011771號