springboot之SpringApplication生命周期和事件機制解讀
本文將以SpringApplication的啟動流程以及生命周期各時期發(fā)出的Event事件為主線,結(jié)合每個生命周期內(nèi)完成的事件介紹,真正實現(xiàn)一文讓你總覽Spring Boot的全貌,這對讀者深入理解Spring Boot,以及整合進(jìn)Spring Cloud都將非常重要。
接下來我們先看下SpringApplication生命周期事件流程圖,然后再講解各個事件的詳情:
1、SpringApplicationEvent
它是和SpringApplication生命周期有關(guān)的所有事件的父類,@since 1.0.0
public abstract class SpringApplicationEvent extends ApplicationEvent { private final String[] args; public SpringApplicationEvent(SpringApplication application, String[] args) { super(application); this.args = args; } public SpringApplication getSpringApplication() { return (SpringApplication) getSource(); } public final String[] getArgs() { return this.args; } }
它是抽象類,擴展自Spring Framwork的ApplicationEvent,確保了事件和應(yīng)用實體SpringApplication產(chǎn)生關(guān)聯(lián),它有如下子類,每個事件都代表著SpringApplication不同生命周期所處的位置:
2、ApplicationStartingEvent
調(diào)用getRunListeners()方法, 實例化一個SpringApplicationRunListeners對象, SpringApplicationRunListeners的構(gòu)造參數(shù)通過getSpringFactoriesInstances()方法獲得,這個方法獲取的一個EventPublishingRunListener對象, 所以調(diào)用的是EventPublishingRunListener#starting()方法
ApplicationStartingEvent構(gòu)造方法中傳遞了一個SpringApplication對象和args參數(shù)。
一直傳遞到了父類EventObject,將SpringApplication對象存放在source變量中。
public class SpringApplication { //run方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //本文分析的重點,發(fā)布啟動事件ApplicationStartingEvent //獲取SpringApplicationRunListener的子類listener SpringApplicationRunListeners listeners = getRunListeners(args); //執(zhí)行其starting()方法 listeners.starting(); .... } //獲取SpringApplicationRunListener的子類listener private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; //調(diào)用getSpringFactoriesInstances方法 //獲取SpringApplicationRunListener的子類 //子類只有一個,EventPublishingRunListener //實例化了一個SpringApplicationRunListeners對象 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } }
2.1 SpringApplicationRunListeners
SpringApplicationRunListeners是一個比較重要的類, 之后的代碼會經(jīng)常調(diào)用這個方法,內(nèi)部封裝了一個SpringApplicationRunListener的list, 方便以后擴展,目前只有一個EventPublishingRunListener實例,所以spring的事件都是由EventPublishingRunListener發(fā)布的:
//SpringApplicationRunListeners部分源碼 class SpringApplicationRunListeners { private final Log log; //SpringApplicationRunListener的子類對象列表 //listener列表擴展點 private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); } //發(fā)布啟動事件 public void starting() { for (SpringApplicationRunListener listener : this.listeners) { //目前調(diào)用EventPublishingRunListener#starting方法 listener.starting(); } } //其他事件都是相同的代碼 //.... }
2.2 EventPublishingRunListener
EventPublishingRunListener是springboot的事件廣播器, 內(nèi)部封裝了一個SimpleApplicationEventMulticaster對象,用來發(fā)布springboot加載過程中的各個事件
- 事件源SpringApplication對象
- 事件SpringApplicationEvent對象
- 事件發(fā)布器是EventPublishingRunListener, 正在的事件發(fā)布器是其內(nèi)部SimpleApplicationEventMulticaster成員變量
- 事件監(jiān)聽器SpringApplication維護(hù)的listeners, 調(diào)用AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)篩選出支持ApplicationEvent的listeners
//EventPublishingRunListener部分源碼 public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { //SpringApplication對象 private final SpringApplication application; //命令函參數(shù) private final String[] args; //事件廣播器 private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); // 通過application.getListeners(),獲取到Listener列表 // ConfigFileApplicationListener // AnsiOutputApplicationListener // LoggingApplicationListener // ClasspathLoggingApplicationListener // BackgroundPreinitializer // DelegatingApplicationListener // ParentContextCloserApplicationListener // ClearCachesApplicationListener // FileEncodingApplicationListener // LiquibaseServiceLocatorApplicationListener for (ApplicationListener<?> listener : application.getListeners()) { //將listener添加到事件廣播器initialMulticaster this.initialMulticaster.addApplicationListener(listener); } } @Override public void starting() { // 廣播器廣播ApplicationStartingEvent事件 this.initialMulticaster.multicastEvent( new ApplicationStartingEvent(this.application, this.args)); } //其他事件發(fā)布都是相同的代碼 //... }
2.3 SimpleApplicationEventMulticaster
springboot默認(rèn)事件廣播器, 有三個重要方法, 用于發(fā)布spring啟動過程中的各個事件:
- addApplicationListener() 添加監(jiān)聽器listener
- multicastEvent() 廣播spring事件
- invokeListener() 實現(xiàn)每個listener的onApplicationEvent()方法
父類AbstractApplicationEventMulticaster,封裝了四個重要方法:
- addApplicationListener添加listener
- addApplicationListenerBean添加注入的listener bean名稱
- removeApplicationListener刪除listener
- removeApplicationListenerBean刪除注入的listener bean名稱
- getApplicationListeners()先從緩存retrieverCache獲取listener,如果緩存不存在, 封裝數(shù)據(jù)放入緩存中, 增刪listener的時候, 緩存retrieverCache會被清空
以下是父類AbstractApplicationEventMulticaster源碼分析:
//抽象事件廣播器 public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { //監(jiān)聽器遍歷器 //成員變量applicationListeners Set維護(hù)了application中包含的listeners, //成員變量applicationListenerBeans Set維護(hù)了注入的listener bean名稱 private final ListenerRetriever defaultRetriever = new ListenerRetriever(false); //調(diào)用getApplicationListeners()方法之后 //緩存spring事件以及對應(yīng)的listener列表 final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64); private Object retrievalMutex = this.defaultRetriever; @Override public void addApplicationListener(ApplicationListener<?> listener) { synchronized (this.retrievalMutex) { //監(jiān)聽器已經(jīng)被加載過, //先執(zhí)行刪除操作,防止重復(fù)執(zhí)行 Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); //清空緩存 this.retrieverCache.clear(); } } /** * 獲取支持監(jiān)聽event的listener * 這里使用了單例模式 */ protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); //嘗試從ConcurrentHashMap緩存中取出listener列表 ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { //雙重檢查鎖定 //當(dāng)多線程訪問的時候, //之前retriever多個線程否返回null, //此時鎖住this.retrievalMutex //防止多次實例化 synchronized (this.retrievalMutex) { //再嘗試從cache中獲取 retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } //生成Key和Value放入緩存中 retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { //沒有緩存ListenerRetriever,那么就不需要同步 return retrieveApplicationListeners(eventType, sourceType, null); } } //retrieveApplicationListeners方法中 //調(diào)用了supportsEvent方法 //supportsEvent使用了適配器模式 protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); } }
SimpleApplicationEventMulticaster源碼分析:
廣播事件, 然后實現(xiàn)每個listener的onApplicationEvent()方法
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { @Nullable private Executor taskExecutor; @Nullable private ErrorHandler errorHandler; /** * 構(gòu)造函數(shù) * taskExecutor和errorHandler都是null */ public SimpleApplicationEventMulticaster() { } /** * 廣播事件 * @param event 事件 * @param eventType 事件類型 */ @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); //調(diào)用父類getApplicationListeners方法 //遍歷所有支持ApplicationStartingEvent事件的監(jiān)聽器 //LoggingApplicationListener //BackgroundPreinitializer //DelegatingApplicationListener //LiquibaseServiceLocatorApplicationListener for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { //此時的executor為null Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { //調(diào)用listener invokeListener(listener, event); } } } /** * 具體調(diào)用監(jiān)聽器的方法 * @param listener 監(jiān)聽器 * @param event 事件 */ private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { //調(diào)用listener的onApplicationEvent方法 listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass())) { Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }
默認(rèn)情況下,有4個監(jiān)聽器監(jiān)聽ApplicationStartingEvent事件:
- LoggingApplicationListener:日志監(jiān)聽器,配置日志;@since 2.0.0。對日志系統(tǒng)抽象LoggingSystem執(zhí)行實例化以及初始化之前的操作,默認(rèn)使用的是基于Logback的LogbackLoggingSystem
- BackgroundPreinitializer:啟動一個后臺進(jìn)行對一些類進(jìn)行預(yù)熱。如ValidationInitializer、JacksonInitializer…,因為這些組件有第一次觸發(fā)的特點(并且首次初始化均還比較耗時),所以使用后臺線程先預(yù)熱效果更佳
- DelegatingApplicationListener:代理監(jiān)聽器, 繼續(xù)發(fā)布事件;它監(jiān)聽的是ApplicationEvent,而實際上只會ApplicationEnvironmentPreparedEvent到達(dá)時生效,所以此處忽略
- LiquibaseServiceLocatorApplicationListener:將liquibas替換為可以和spring配合工作的版本
總結(jié):此事件節(jié)點結(jié)束時,SpringApplication完成了一些實例化相關(guān)的動作:本實例實例化、本實例屬性賦值、日志系統(tǒng)實例化等。
3、ApplicationEnvironmentPreparedEvent
@since 1.0.0。該事件節(jié)點是最為重要的一個節(jié)點之一,因為對于Spring應(yīng)用來說,環(huán)境抽象Enviroment簡直太重要了,它是最為基礎(chǔ)的元數(shù)據(jù),決定著程序的構(gòu)建和走向,所以構(gòu)建的時機是比較早的。
完成的事件內(nèi)容:
封裝命令行參數(shù)(main方法的args)到ApplicationArguments里面
創(chuàng)建出一個環(huán)境抽象實例ConfigurableEnvironment的實現(xiàn)類,并且填入值:Profiles配置和Properties屬性,默認(rèn)內(nèi)容如下(注意,這只是初始狀態(tài),后面還會改變):
發(fā)送ApplicationEnvironmentPreparedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行;對環(huán)境抽象Enviroment的填值,均是由監(jiān)聽此事件的監(jiān)聽器去完成
bindToSpringApplication(environment):把環(huán)境屬性中spring.main.xxx = xxx綁定到當(dāng)前的SpringApplication實例屬性上,如常用的spring.main.allow-bean-definition-overriding=true會被綁定到當(dāng)前SpringApplication實例的對應(yīng)屬性上
監(jiān)聽此事件的監(jiān)聽器:
默認(rèn)情況下,有9個監(jiān)聽器監(jiān)聽ApplicationEnvironmentPreparedEvent事件:
1.BootstrapApplicationListener:
來自SpringCloud。優(yōu)先級最高,用于啟動/創(chuàng)建Spring Cloud的應(yīng)用上下文。需要注意的是:到此時SB的上下文ApplicationContext還并沒有創(chuàng)建哦。這個流程“嵌套”特別像Bean初始化流程:初始化Bean A時,遇到了Bean B,就需要先去完成Bean B的初始化,再回頭來繼續(xù)完成Bean A的步驟。
說明:在創(chuàng)建SC的應(yīng)用的時候,使用的也是SpringApplication#run()完成的(非web),因此也會走下一整套SpringApplication的生命周期邏輯,所以務(wù)必區(qū)分。特別是這種case會讓“絕大多數(shù)”初始化器、監(jiān)聽器等執(zhí)行多次,若你有那種只需要執(zhí)行一次的需求(比如只想讓SB容器生命周期內(nèi)執(zhí)行,SC生命周期不執(zhí)行),請務(wù)必自行處理,否則會被執(zhí)行多次而帶來不可預(yù)知的結(jié)果;SC應(yīng)用上下文讀取的外部化配置文件名默認(rèn)是:bootstrap,使用的也是ConfigFileApplicationListener完成的加載/解析;
2.LoggingSystemShutdownListener:
來自SpringCloud。對LogbackLoggingSystem先清理,再重新初始化一次,效果同上個事件,相當(dāng)于重新來了一次,畢竟現(xiàn)在有Enviroment環(huán)境;
3.ConfigFileApplicationListener:
@since 1.0.0。它也許是最重要的一個監(jiān)聽器。做了如下事情:
加載SPI配置的所有的EnvironmentPostProcessor實例,并且排好序。
需要注意的是:ConfigFileApplicationListener也是個EnvironmentPostProcessor,也會參與排序; 排好序后,分別一個個的執(zhí)行以下EnvironmentPostProcessor
4.AnsiOutputApplicationListener:
@since 1.2.0。讓你的終端(可以是控制臺、可以是日志文件)支持Ansi彩色輸出,使其更具可讀性。當(dāng)然前提是你的終端支持ANSI顯示。參考類:AnsiOutput。你可通過spring.output.ansi.enabled = xxx配置,可選值是:DETECT/ALWAYS/NEVER,一般不動即可。另外,針對控制臺可以單獨配置:spring.output.ansi.console-available = true/false
5.LoggingApplicationListener:
@since 2.0.0。根據(jù)Enviroment環(huán)境完成initialize()初始化動作:日志等級、日志格式模版等;值得注意的是:它這步相當(dāng)于在ApplicationStartingEvent事件基礎(chǔ)上進(jìn)一步完成了初始化(上一步只是實例化);
6.ClasspathLoggingApplicationListener:
@since 2.0.0。用于把classpath路徑以log.debug()輸出;值得注意的是:classpath類路徑是有N多個的Arrays.toString(((URLClassLoader) classLoader).getURLs()),也就是說每個.jar里都屬于classpath的范疇;
7.BackgroundPreinitializer:
本事件達(dá)到時無動作;
8.DelegatingApplicationListener:
執(zhí)行通過外部化配置context.listener.classes = xxx,xxx的監(jiān)聽器們,然后把該事件廣播給他們,執(zhí)行監(jiān)聽此事件的監(jiān)聽器;這麼做的好處:可以通過屬性文件外部化配置監(jiān)聽器,而不一定必須寫在spring.factories里,更具彈性;
9.FileEncodingApplicationListener:
檢測當(dāng)前系統(tǒng)環(huán)境的file.encoding和spring.mandatory-file-encoding設(shè)置的值是否一樣,如果不一樣則拋出異常如果不配置spring.mandatory-file-encoding則不檢查;
總結(jié):此事件節(jié)點結(jié)束時,Spring Boot的環(huán)境抽象Enviroment已經(jīng)準(zhǔn)備完畢,但此時其上下文ApplicationContext還沒有創(chuàng)建,但是Spring Cloud的應(yīng)用上下文(引導(dǎo)上下文)已經(jīng)全部初始化完畢哦,所以SC管理的外部化配置也應(yīng)該都進(jìn)入到了SB里面。
如下圖所示(這是基本上算是Enviroment的最終態(tài)了):
4、ApplicationContextInitializedEvent
@since 2.1.0,非常新的一個事件。當(dāng)SpringApplication的上下文ApplicationContext準(zhǔn)備好后,對單例Bean們實例化之前,發(fā)送此事件。
所以此事件又可稱為:contextPrepared事件。
完成的事件內(nèi)容:
上下文實例已經(jīng)有了,那么就開始對它進(jìn)行一些參數(shù)的設(shè)置:
- 首先最重要的便是把已經(jīng)準(zhǔn)備好的環(huán)境Enviroment環(huán)境設(shè)置給它
- 設(shè)置些beanNameGenerator、resourceLoader、ConversionService等組件
- 實例化所有的ApplicationContextInitializer上下文初始化器,并且排序好后挨個執(zhí)行它(這個很重要),默認(rèn)有如下截圖這些初始化器此時要執(zhí)行:
監(jiān)聽此事件的監(jiān)聽器:監(jiān)聽此事件默認(rèn)情況下,有2個監(jiān)聽器監(jiān)聽ApplicationContextInitializedEvent事件:
- BackgroundPreinitializer:本事件達(dá)到時無動作
- DelegatingApplicationListener:本事件達(dá)到時無動作
總結(jié):此事件節(jié)點結(jié)束時,完成了應(yīng)用上下文ApplicationContext的準(zhǔn)備工作,并且執(zhí)行所有注冊的上下文初始化器ApplicationContextInitializer。但是此時,單例Bean是仍舊還沒有初始化,并且WebServer也還沒有啟動;
5、ApplicationPreparedEvent
@since 1.0.0。截止到上個事件ApplicationContextInitializedEvent,應(yīng)用上下文ApplicationContext充其量叫實例化好了,但是還剩下很重要的事沒做,便是此事件的執(zhí)行內(nèi)容了;
完成的事件內(nèi)容:
- 把applicationArguments、printedBanner等都作為一個Bean放進(jìn)Bean工廠里(因此你就可以@Autowired注入的哦)
比如:有了Banner這個Bean,你可以在你任何想要輸出的地方輸出一個Banner,而不僅僅是啟動時只會輸出一次了;
- 若lazyInitialization = true延遲初始化,那就向Bean工廠放一個:new LazyInitializationBeanFactoryPostProcessor()
該處理器@since 2.2.0。該處理器的作用是:對所有的Bean(通過LazyInitializationExcludeFilter接口指定的排除在外)全部.setLazyInit(true),延遲初始化;
根據(jù)primarySources和allSources,交給BeanDefinitionLoader(SB提供的實現(xiàn))實現(xiàn)加載Bean的定義信息,它支持4種加載方式(4種源):
- AnnotatedBeanDefinitionReader -> 基于注解
- XmlBeanDefinitionReader -> 基于xml配置
- GroovyBeanDefinitionReader -> Groovy文件
- ClassPathBeanDefinitionScanner -> classpath中加載(不同的源使用了不同的load加載方式)
發(fā)送ApplicationPreparedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行
總結(jié):此事件節(jié)點結(jié)束時,應(yīng)用上下文ApplicationContext初始化完成,該賦值的賦值了,Bean定義信息也已全部加載完成。但是,單例Bean還沒有被實例化,web容器依舊還沒啟動。
6、ApplicationStartedEvent
@since 2.0.0。截止到此,應(yīng)用已經(jīng)準(zhǔn)備就緒,并且通過監(jiān)聽器、初始化器等完成了非常多的工作了,但仍舊剩下被認(rèn)為最為重要的初始化單例Bean動作還沒做、web容器(如Tomcat)還沒啟動,這便是這個周期所要做的事。
完成的事件內(nèi)容:
啟動Spring容器:AbstractApplicationContext#refresh(),這個步驟會做很多事,比如會實例化單例Bean;該步驟屬于Spring Framework的核心內(nèi)容范疇,做了很多事,請參考Spring核心技術(shù);在Spring容器refresh()啟動完成后,WebServer也隨之完成啟動,成功監(jiān)聽到對應(yīng)端口;
輸出啟動成功的日志:Started Application in xxx seconds (JVM running for xxx);
發(fā)送ApplicationStartedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行;
- callRunners():依次執(zhí)行容器內(nèi)配置的ApplicationRunner/CommandLineRunner的Bean實現(xiàn)類,支持sort排序:
- ApplicationRunner:@since 1.3.0,入?yún)⑹茿pplicationArguments,先執(zhí)行(推薦使用)
- CommandLineRunner:@since 1.0.0,入?yún)⑹荢tring… args,后執(zhí)行(不推薦使用)
監(jiān)聽此事件的監(jiān)聽器:
默認(rèn)情況下,有3個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:
1.前兩個不用再解釋了吧:本事件達(dá)到時無動作
2.TomcatMetricsBinder:@since 2.1.0。和監(jiān)控相關(guān):將你的tomcat指標(biāo)信息TomcatMetrics綁定到MeterRegistry,從而就能收集到相關(guān)指標(biāo)了
總結(jié):此事件節(jié)點結(jié)束時,SpringApplication的生命周期到這一步,正常的啟動流程就全部完成了。也就說Spring Boot應(yīng)用可以正常對對外提供服務(wù)了。
7、ApplicationReadyEvent
@since 1.3.0。該事件所處的生命周期可認(rèn)為基本和ApplicationStartedEvent相同,僅是在其后執(zhí)行而已,兩者中間并無其它特別的動作,但是監(jiān)聽此事件的監(jiān)聽器們還是蠻重要的。
監(jiān)聽此事件的監(jiān)聽器:
默認(rèn)情況下,有4個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:
- SpringApplicationAdminMXBeanRegistrar:當(dāng)此事件到達(dá)時,告訴Admin Spring應(yīng)用已經(jīng)ready,可以使用啦。
- 中間這兩個不用再解釋了吧:本事件達(dá)到時無動作
- RefreshEventListener:當(dāng)此事件到達(dá)時,告訴Spring應(yīng)用已經(jīng)ready了,接下來便可以執(zhí)行ContextRefresher.refresh()
總結(jié):此事件節(jié)點結(jié)束時,應(yīng)用已經(jīng)完完全全的準(zhǔn)備好了,并且也已經(jīng)完成了相關(guān)組件的周知工作。
8、ApplicationFailedEvent
當(dāng)SpringApplication在啟動時拋出異常:可能是端口綁定、也可能是你自定義的監(jiān)聽器你寫了個bug等,就會“可能”發(fā)送此事件。
完成的事件內(nèi)容:
- 得到異常的退出碼ExitCode,然后發(fā)送ExitCodeEvent事件(非生命周期事件)
- 發(fā)送ApplicationFailedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行
監(jiān)聽此事件的監(jiān)聽器:
默認(rèn)情況下,有6個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:
- LoggingApplicationListener:執(zhí)行l(wèi)oggingSystem.cleanUp()清理資源
- ClasspathLoggingApplicationListener:輸出一句debug日志:Application failed to start with classpath: …
- 中間這兩個不用再解釋了吧:本事件達(dá)到時無動作
- ConditionEvaluationReportLoggingListener:自動配置輸出報告,輸出錯誤日志唄:特別方便你查看和錯誤定位;
- BootstrapApplicationListener.CloseContextOnFailureApplicationListener:執(zhí)行context.close()
總結(jié):此事件節(jié)點結(jié)束時,會做一些釋放資源的操作。一般情況下:我們并不需要監(jiān)聽到此事件;
最后
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis-plus添加數(shù)據(jù)時id自增問題及解決
這篇文章主要介紹了mybatis-plus添加數(shù)據(jù)時id自增問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01解讀@Scheduled任務(wù)調(diào)度/定時任務(wù)非分布式
這篇文章主要介紹了解讀@Scheduled任務(wù)調(diào)度/定時任務(wù)非分布式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例
這篇文章主要介紹了spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12