Spring?Boot?完整啟動(dòng)流程詳解
本文完整解析 Spring Boot 啟動(dòng)流程的 9 個(gè)核心階段,結(jié)合源碼與實(shí)戰(zhàn)場景,幫助開發(fā)者深入理解框架運(yùn)行機(jī)制。適用于面試準(zhǔn)備和技術(shù)原理學(xué)習(xí)。
一、啟動(dòng)入口:SpringApplication.run()
public static ConfigurableApplicationContext run(Class<?> primarySource, String[] args) {
return new SpringApplication(primarySource).run(args);
}二、完整啟動(dòng)流程(9大核心階段)
階段1:初始化啟動(dòng)計(jì)時(shí)器
StopWatch stopWatch = new StopWatch(); stopWatch.start();
階段2:監(jiān)聽器初始化與啟動(dòng)事件
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); // 發(fā)布ApplicationStartingEvent
- ??作用??:通知所有
SpringApplicationRunListener啟動(dòng)開始 - ??擴(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(自動(dòng)配置入口)
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注冊BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件廣播器
initApplicationEventMulticaster();
// 9. ★ Web容器啟動(dòng)關(guān)鍵步驟
onRefresh();
// 10. 注冊監(jiān)聽器
registerListeners();
// 11. ★★★ 實(shí)例化所有非延遲單例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
} catch (BeansException ex) {
// 異常處理...
}
}刷新階段重點(diǎn)說明:
??自動(dòng)裝配觸發(fā)點(diǎn)??(invokeBeanFactoryPostProcessors):
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(
beanFactory, getBeanFactoryPostProcessors());
// 這里會(huì)處理@SpringBootApplication->加載自動(dòng)配置類
}??嵌入式容器啟動(dòng)點(diǎn)??(onRefresh):
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 啟動(dòng)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ù)、啟動(dòng)定時(shí)任務(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啟動(dòng)流程全景圖
graph TD
A[SpringApplication.run] --> B[啟動(dòng)計(jì)時(shí)器]
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. 自動(dòng)裝配機(jī)制
- 通過
@EnableAutoConfiguration引入自動(dòng)配置 AutoConfigurationImportSelector掃描META-INF/spring.factories- 使用
@Conditional系列注解實(shí)現(xiàn)條件裝配
2. 嵌入式容器啟動(dòng)
- ??Servle容器??:自動(dòng)探測并初始化Tomcat/Jetty/Undertow
- ??Reactive容器??:支持Netty/Reactor等
- ??啟動(dòng)時(shí)機(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 啟動(dòng)流程詳解的文章就介紹到這了,更多相關(guān)Spring Boot 啟動(dòng)流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot?啟動(dòng)流程追蹤方法分享
- SpringBoot熱部署啟動(dòng)關(guān)閉流程詳解
- SpringBoot啟動(dòng)流程SpringApplication準(zhǔn)備階段源碼分析
- SpringBoot啟動(dòng)流程入口參數(shù)創(chuàng)建對象源碼分析
- SpringBoot自動(dòng)配置與啟動(dòng)流程詳細(xì)分析
- SpringBoot超詳細(xì)分析啟動(dòng)流程
- Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置詳解
- SpringBoot項(xiàng)目運(yùn)行jar包啟動(dòng)的步驟流程解析
相關(guān)文章
Java 入門圖形用戶界面設(shè)計(jì)之事件處理上
圖形界面(簡稱GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對于用戶來說在視覺上更易于接受,本篇精講Java語言中關(guān)于圖形用戶界面的事件處理2022-02-02
Spring Cloud Gateway 獲取請求體(Request Body)的多種方法
這篇文章主要介紹了Spring Cloud Gateway 獲取請求體(Request Body)的多種方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
MyBatis Mapper.xml入?yún)ist使用in函數(shù)問題
文章主要講述了在使用MyBatis的Mapper.xml文件時(shí),如何正確地在in函數(shù)中使用List作為入?yún)?作者強(qiáng)調(diào)了完整拷貝<if>...</if>格式的重要性,并指出稍微的改動(dòng)就會(huì)導(dǎo)致錯(cuò)誤2025-02-02
SpringBoot實(shí)現(xiàn)Logback輸出日志到Kafka方式
本文介紹了如何在SpringBoot應(yīng)用中通過自定義Appender實(shí)現(xiàn)Logback輸出日志到Kafka,包括配置maven依賴、Kafka工具類和logback.xml配置2025-02-02
SpringBoot調(diào)用對方webService接口的幾種方法示例
平常我們開發(fā)調(diào)用接口一般會(huì)用到幾種數(shù)據(jù)格式,比如有restful的,這個(gè)是目前最流行的,也是最簡單開發(fā)的,還有一種就是webservice數(shù)據(jù)格式,本文給大家介紹了幾種SpringBoot調(diào)用對方webService接口的方法,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下2023-11-11

