Spring?Boot?完整啟動流程詳解
本文完整解析 Spring Boot 啟動流程的 9 個核心階段,結(jié)合源碼與實(shí)戰(zhàn)場景,幫助開發(fā)者深入理解框架運(yùn)行機(jī)制。適用于面試準(zhǔn)備和技術(shù)原理學(xué)習(xí)。
一、啟動入口:SpringApplication.run()
public static ConfigurableApplicationContext run(Class<?> primarySource, String[] args) {
return new SpringApplication(primarySource).run(args);
}二、完整啟動流程(9大核心階段)
階段1:初始化啟動計(jì)時器
StopWatch stopWatch = new StopWatch(); stopWatch.start();
階段2:監(jiān)聽器初始化與啟動事件
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); // 發(fā)布ApplicationStartingEvent
- ??作用??:通知所有
SpringApplicationRunListener啟動開始 - ??擴(kuò)展點(diǎn)??:可自定義監(jiān)聽器實(shí)現(xiàn)初始化日志、監(jiān)控等操作
階段3:環(huán)境準(zhǔn)備與環(huán)境事件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArgs);
graph TD
A[創(chuàng)建Environment對象] --> B[加載配置源]
B --> C[解析Profile配置]
C --> D[轉(zhuǎn)換配置屬性]
D --> E[發(fā)布ApplicationEnvironmentPreparedEvent]階段4:打印Banner
Banner printedBanner = printBanner(environment);
- 默認(rèn)打印SPRING BOOT字符Logo
- 支持自定義banner.txt文件或完全禁用
階段5:創(chuàng)建應(yīng)用上下文
context = createApplicationContext();
??上下文類型判斷邏輯:??
protected ConfigurableApplicationContext createApplicationContext() {
return switch (this.webApplicationType) {
case SERVLET -> new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE -> new AnnotationConfigReactiveWebServerApplicationContext();
default -> new AnnotationConfigApplicationContext(); // 非Web應(yīng)用
};
}階段6:上下文預(yù)處理
prepareContext(context, environment, listeners, appArgs, printedBanner);
??核心步驟:??
- 關(guān)聯(lián)環(huán)境配置到上下文
- 應(yīng)用
ApplicationContextInitializer擴(kuò)展點(diǎn) - 發(fā)布
ApplicationContextInitializedEvent - 注冊主配置類(
@SpringBootApplication注解類) - 發(fā)布
ApplicationPreparedEvent
階段7:★★★ 核心刷新階段 ★★★
refreshContext(context); // 內(nèi)部調(diào)用Spring的refresh()
??Spring Framework的12步刷新流程:??
public void refresh() {
// 1. 準(zhǔn)備刷新
prepareRefresh();
// 2. 獲取BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 準(zhǔn)備BeanFactory
prepareBeanFactory(beanFactory);
try {
// 4. 后置處理BeanFactory
postProcessBeanFactory(beanFactory);
// 5. ★★★ 執(zhí)行BeanFactoryPostProcessor(自動配置入口)
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注冊BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件廣播器
initApplicationEventMulticaster();
// 9. ★ Web容器啟動關(guān)鍵步驟
onRefresh();
// 10. 注冊監(jiān)聽器
registerListeners();
// 11. ★★★ 實(shí)例化所有非延遲單例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
} catch (BeansException ex) {
// 異常處理...
}
}刷新階段重點(diǎn)說明:
??自動裝配觸發(fā)點(diǎn)??(invokeBeanFactoryPostProcessors):
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(
beanFactory, getBeanFactoryPostProcessors());
// 這里會處理@SpringBootApplication->加載自動配置類
}??嵌入式容器啟動點(diǎn)??(onRefresh):
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 啟動Tomcat/Jetty
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}??Bean實(shí)例化點(diǎn)??(finishBeanFactoryInitialization):
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化所有非延遲單例Bean
beanFactory.preInstantiateSingletons();
}階段8:刷新后處理
afterRefresh(context, appArgs);
- ??默認(rèn)空方法??,開發(fā)人員可重寫實(shí)現(xiàn)自定義邏輯
- 典型應(yīng)用:初始化數(shù)據(jù)庫數(shù)據(jù)、啟動定時任務(wù)等
階段9:事件通知與Runner執(zhí)行
stopWatch.stop(); listeners.started(context); // ApplicationStartedEvent callRunners(context, appArgs); // 執(zhí)行ApplicationRunner/CommandLineRunner listeners.running(context); // ApplicationReadyEvent
Runner執(zhí)行機(jī)制:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : runners) {
if (runner instanceof ApplicationRunner) {
((ApplicationRunner) runner).run(args);
}
if (runner instanceof CommandLineRunner) {
((CommandLineRunner) runner).run(args.getSourceArgs());
}
}
}三、Spring Boot啟動流程全景圖
graph TD
A[SpringApplication.run] --> B[啟動計(jì)時器]
B --> C[初始化監(jiān)聽器]
C --> D[發(fā)布StartingEvent]
D --> E[準(zhǔn)備Environment]
E --> F[打印Banner]
F --> G[創(chuàng)建上下文]
G --> H[預(yù)處理上下文]
H --> I[refreshContext核心]
I --> J[后置處理]
J --> K[發(fā)布StartedEvent]
K --> L[執(zhí)行Runner]
L --> M[發(fā)布ReadyEvent]四、關(guān)鍵技術(shù)原理
1. 自動裝配機(jī)制
- 通過
@EnableAutoConfiguration引入自動配置 AutoConfigurationImportSelector掃描META-INF/spring.factories- 使用
@Conditional系列注解實(shí)現(xiàn)條件裝配
2. 嵌入式容器啟動
- ??Servle容器??:自動探測并初始化Tomcat/Jetty/Undertow
- ??Reactive容器??:支持Netty/Reactor等
- ??啟動時機(jī)??:在
onRefresh()階段創(chuàng)建WebServer
3. 配置加載順序
1. 命令行參數(shù)
2. 系統(tǒng)環(huán)境變量
3. JNDI屬性
4. Java系統(tǒng)屬性
5. Profile-specific配置(application-{profile}.yml)
6. 主配置文件(application.yml)
7. @Configuration注解的@PropertySource
8. SpringApplication.setDefaultProperties
到此這篇關(guān)于Spring Boot 啟動流程詳解的文章就介紹到這了,更多相關(guān)Spring Boot 啟動流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring-boot 2.3.x源碼基于Gradle編譯過程詳解
這篇文章主要介紹了Spring-boot 2.3.x源碼基于Gradle編譯過程詳解,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
java使用lambda表達(dá)式對List集合進(jìn)行操作技巧(JDK1.8)
這篇文章主要介紹了java使用lambda表達(dá)式對List集合進(jìn)行操作技巧適用jdk1.8,感興趣的朋友跟著小編一起看看實(shí)現(xiàn)代碼吧2018-06-06
Java基于命令行調(diào)用Python腳本的方法詳解
這篇文章主要為大家詳細(xì)介紹了Java如何基于命令行實(shí)現(xiàn)調(diào)用Python腳本的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-06-06
IntelliJ Idea 2017注冊碼免費(fèi)激活方法
IDEA 全稱 IntelliJ IDEA,是Java語言開發(fā)的集成環(huán)境,IntelliJ在業(yè)界被公認(rèn)為最好的java開發(fā)工具之一。下面給大家介紹IntelliJ Idea 2017注冊碼免費(fèi)激活方法,需要的朋友參考下2018-01-01
Java設(shè)計(jì)模式之享元模式(Flyweight Pattern)詳解
享元模式(Flyweight Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,旨在減少對象的數(shù)量,以節(jié)省內(nèi)存空間和提高性能,本文將詳細(xì)的給大家介紹一下Java享元模式,需要的朋友可以參考下2023-07-07
SpringBoot中AOP的動態(tài)匹配和靜態(tài)匹配詳解
這篇文章主要介紹了SpringBoot中AOP的動態(tài)匹配和靜態(tài)匹配詳解,在創(chuàng)建代理的時候?qū)δ繕?biāo)類的每個連接點(diǎn)使用靜態(tài)切點(diǎn)檢查,如果僅通過靜態(tài)切點(diǎn)檢查就可以知道連接點(diǎn)是不匹配的,則在運(yùn)行時就不再進(jìn)行動態(tài)檢查了,需要的朋友可以參考下2023-09-09
Java讀取項(xiàng)目json文件并轉(zhuǎn)為JSON對象的操作
這篇文章主要介紹了Java讀取項(xiàng)目json文件并轉(zhuǎn)為JSON對象的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08

