SpringBoot之ApplicationRunner解析(spring容器啟動(dòng)完成執(zhí)行的類)
SpringBoot ApplicationRunner解析
在項(xiàng)目中,可能會遇到這樣一個(gè)問題:在項(xiàng)目啟動(dòng)完成之后,緊接著執(zhí)行一段代碼。
在SpringBoot中,提供了一個(gè)接口:ApplicationRunner。
該接口中,只有一個(gè)run方法,他執(zhí)行的時(shí)機(jī)是:spring容器啟動(dòng)完成之后,就會緊接著執(zhí)行這個(gè)接口實(shí)現(xiàn)類的run方法。
@Component public class PublishEndpoint implements ApplicationRunner{ ?? ?@Override ?? ?public void run(ApplicationArguments applicationArguments) throws Exception { ?? ??? ?//do something ?? ?} }
這里有幾點(diǎn)說明:
- 這個(gè)實(shí)現(xiàn)類,要注入到spring容器中,這里使用了@Component注解;
- 在同一個(gè)項(xiàng)目中,可以定義多個(gè)ApplicationRunner的實(shí)現(xiàn)類,他們的執(zhí)行順序通過注解@Order注解或者再實(shí)現(xiàn)Ordered接口來實(shí)現(xiàn)。
- run方法的參數(shù):ApplicationArguments可以獲取到當(dāng)前項(xiàng)目執(zhí)行的命令參數(shù)。(比如把這個(gè)項(xiàng)目打成jar執(zhí)行的時(shí)候,帶的參數(shù)可以通過ApplicationArguments獲取到);
- 由于該方法是在容器啟動(dòng)完成之后,才執(zhí)行的,所以,這里可以從spring容器中拿到其他已經(jīng)注入的bean。
@SpringBootApplication啟動(dòng)流程詳解
帶你深入探索SpringApplication執(zhí)行流程
SpringApplication的run方法的實(shí)現(xiàn)是我們本次探索之旅的主要線路,該方法的主要流程歸納如下:
1:如果我們使用的是SpringApplication的靜態(tài)run方法,那么,這個(gè)方法里面首先要?jiǎng)?chuàng)建一個(gè)SpringApplication對象實(shí)例,然后調(diào)用這個(gè)創(chuàng)建好的SpringApplication的實(shí)例方法。在SpringApplication實(shí)例初始化的時(shí)候,它會提前做幾件事情:
- 根據(jù)classpath里面是否存在某個(gè)特征類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應(yīng)該創(chuàng)建一個(gè)為Web應(yīng)用使用的ApplicationContext類型。
- 使用SpringFactoriesLoader在應(yīng)用的classpath中查找并加載所有可用的ApplicationContextInitializer。
- 使用SpringFactoriesLoader在應(yīng)用的classpath中查找并加載所有可用的ApplicationListener。
- 推斷并設(shè)置main方法的定義類。
2: SpringApplication實(shí)例初始化完成并且完成設(shè)置后,就開始執(zhí)行run方法的邏輯了,方法執(zhí)行伊始,首先遍歷執(zhí)行所有通過SpringFactoriesLoader可以查找到并加載的SpringApplicationRunListener。調(diào)用它們的started()方法,告訴這些SpringApplicationRunListener,“嘿,SpringBoot應(yīng)用要開始執(zhí)行咯!”。
3: 創(chuàng)建并配置當(dāng)前Spring Boot應(yīng)用將要使用的Environment(包括配置要使用的PropertySource以及Profile)。
4:遍歷調(diào)用所有SpringApplicationRunListener的environmentPrepared()的方法,告訴他們:“當(dāng)前SpringBoot應(yīng)用使用的Environment準(zhǔn)備好了咯!”。
5:如果SpringApplication的showBanner屬性被設(shè)置為true,則打印banner。 【banner:英文廣告橫幅,在這里面指的是運(yùn)行時(shí)輸出的SpringBoot,還可以進(jìn)行修改】
6: 根據(jù)用戶是否明確設(shè)置了applicationContextClass類型以及初始化階段的推斷結(jié)果,決定該為當(dāng)前SpringBoot應(yīng)用創(chuàng)建什么類型的ApplicationContext并創(chuàng)建完成,然后根據(jù)條件決定是否添加ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當(dāng)然,最重要的,將之前準(zhǔn)備好的Environment設(shè)置給創(chuàng)建好的ApplicationContext使用。 【ShutdownHook :停止服務(wù)】
7: ApplicationContext創(chuàng)建好之后,SpringApplication會再次借助Spring-FactoriesLoader,查找并加載classpath中所有可用的ApplicationContext-Initializer,然后遍歷調(diào)用這些ApplicationContextInitializer的initialize(applicationContext)方法來對已經(jīng)創(chuàng)建好的ApplicationContext進(jìn)行進(jìn)一步的處理。
8:遍歷調(diào)用所有SpringApplicationRunListener的contextPrepared()方法。
9:最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置加載到已經(jīng)準(zhǔn)備完畢的ApplicationContext。
10:遍歷調(diào)用所有SpringApplicationRunListener的contextLoaded()方法。
11:調(diào)用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。
12:查找當(dāng)前ApplicationContext中是否注冊有CommandLineRunner,如果有,則遍歷執(zhí)行它們。
13: 正常情況下,遍歷執(zhí)行SpringApplicationRunListener的finished()方法、(如果整個(gè)過程出現(xiàn)異常,則依然調(diào)用所有SpringApplicationRunListener的finished()方法,只不過這種情況下會將異常信息一并傳入處理)
去除事件通知點(diǎn)后,整個(gè)流程如下:
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot rabbitmq整合rabbitmq之消息持久化存儲問題
這篇文章主要介紹了springboot rabbitmq整合rabbitmq之消息持久化存儲問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09手把手教你在eclipse創(chuàng)建第一個(gè)java?web項(xiàng)目并運(yùn)行
Eclipse是用來做開發(fā)的自由集成開發(fā)環(huán)境,這也是很多java程序員會使用的開發(fā)環(huán)境,所以可以使用eclipse創(chuàng)建javaweb項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于如何在eclipse創(chuàng)建第一個(gè)java?web項(xiàng)目并運(yùn)行的相關(guān)資料,需要的朋友可以參考下2023-02-02JAVA對象中使用?static?和?String?基礎(chǔ)探究
這篇文章主要介紹了JAVA對象中使用static和String基礎(chǔ)探究,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09詳解SpringBoot+SpringSecurity+jwt整合及初體驗(yàn)
這篇文章主要介紹了詳解SpringBoot+SpringSecurity+jwt整合及初體驗(yàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-06-06IDEA個(gè)性化設(shè)置注釋模板詳細(xì)講解版
IDEA自帶的注釋模板不是太好用,我本人到網(wǎng)上搜集了很多資料系統(tǒng)的整理了一下制作了一份比較完整的模板來分享給大家,下面這篇文章主要給大家介紹了IDEA個(gè)性化設(shè)置注釋模板的相關(guān)資料,需要的朋友可以參考下2024-01-01Java注解@Conditional與@Profile的使用區(qū)別
這篇文章主要介紹了Java注解@Conditional與@Profile的使用區(qū)別,@Profile和@Conditional是Spring提供的兩種常用機(jī)制,它們可以根據(jù)不同的條件動(dòng)態(tài)決定某些Bean是否加載,從而實(shí)現(xiàn)環(huán)境隔離、模塊選擇、特性開關(guān)等功能,需要的朋友可以參考下2025-05-05詳解Java中NullPointerException的處理方法
這篇文章將帶大家來單獨(dú)看一個(gè)很常見的異常--空指針異常,這個(gè)可以說是每個(gè)Java程序員都必知的異常,所以我們不得不單獨(dú)學(xué)習(xí)一下,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-08-08