SpringApplicationRunListener監(jiān)聽器源碼詳解
前言
springboot提供了兩個(gè)類SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架還提供了一個(gè)ApplicationListener接口,那么這幾個(gè)類或接口的關(guān)系又是如何呢?
首先SpringApplicationRunListeners類是SpringApplicationRunListener接口的代理類,可以批量調(diào)用SpringApplicationRunListener接口方法,SpringApplicationRunListener接口只有一個(gè)實(shí)現(xiàn)類EventPublishingRunListener,其有一個(gè)屬性SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster即是一個(gè)ApplicationListener監(jiān)聽器接口的代理實(shí)現(xiàn)類,可以批量的執(zhí)行監(jiān)聽器的onApplicationEvent方法。
1.SpringApplicationRunListener接口源碼
SpringApplicationRunListener是對(duì)org.springframework.boot.SpringApplication類的run方法進(jìn)行監(jiān)聽,SpringApplicationRunListener實(shí)現(xiàn)類是通過SpringFactoriesLoader類加載(即springboot SPI);并且需要聲明一個(gè)包含SpringApplication實(shí)例及String[]的參數(shù)構(gòu)造方法。
public interface SpringApplicationRunListener { /** * 當(dāng)run方法第一次啟動(dòng)時(shí)立即調(diào)用,可用于非常早期的初始化 */ default void starting() { } /** * 在ApplicationContext創(chuàng)建之前,一旦環(huán)境environment準(zhǔn)備好就調(diào)用。 * @param environment the environment */ default void environmentPrepared(ConfigurableEnvironment environment) { } /** * 在資源(可以理解為配置主類)被加載完成之前,一旦ApplicationContext被創(chuàng)建并準(zhǔn)備好就立馬調(diào)用, * @param context the application context */ default void contextPrepared(ConfigurableApplicationContext context) { } /** * 在資源加載完成之后,但在刷新之前調(diào)用 * @param context the application context */ default void contextLoaded(ConfigurableApplicationContext context) { } /** * 上下文已刷新,應(yīng)用程序已啟動(dòng),但是CommandLineRunner和ApplicationRunner尚未調(diào)用。 * @param context the application context. * @since 2.0.0 */ default void started(ConfigurableApplicationContext context) { } /** * 當(dāng)ApplicationContext已經(jīng)refresh且所有的CommandLineRunner和ApplicationRunner都已被調(diào)用時(shí),在run方法完成之前立即調(diào)用。 * @param context the application context. * @since 2.0.0 */ default void running(ConfigurableApplicationContext context) { } /** * 在運(yùn)行應(yīng)用程序時(shí)發(fā)生故障時(shí)調(diào)用 * @param context 應(yīng)用程序上下文,可能為null(在應(yīng)用程序上下文創(chuàng)建之前) * @param exception the failure * @since 2.0.0 */ default void failed(ConfigurableApplicationContext context, Throwable exception) { }
2.EventPublishingRunListener
SpringApplicationRunListener接口唯一實(shí)現(xiàn)類EventPublishingRunListener
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { //啟動(dòng)類實(shí)例對(duì)象 private final SpringApplication application; //參數(shù) private final String[] args; //ApplicationListener監(jiān)聽器接口代理廣播類 private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); //獲取應(yīng)用程序的監(jiān)聽器類,并循環(huán)添加到代理類的監(jiān)聽器助手屬性對(duì)象中 for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } }
其中application.getListeners()獲取通過SPI方式定義的所有ApplicationListener監(jiān)聽器接口定義的監(jiān)聽器類,其初始化是在SpringApplication類中通過構(gòu)造函數(shù)的方式,如下:
//監(jiān)聽器對(duì)象集合 private List<ApplicationListener<?>> listeners; public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); //通過SPI方式初始化應(yīng)用程序初始化器 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //通過SPI方式獲取ApplicationListener監(jiān)聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
spring.factories配置文件:
# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
3.SpringApplicationRunListeners
SpringApplicationRunListener接口實(shí)現(xiàn)類集合類SpringApplicationRunListeners
class SpringApplicationRunListeners { private final Log log; //存儲(chǔ)SpringApplicationRunListener監(jiān)聽器集合 private final List<SpringApplicationRunListener> listeners; SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) { this.log = log; this.listeners = new ArrayList<>(listeners); } }
4.獲取SpringApplicationRunListeners對(duì)象
org.springframework.boot.SpringApplication#run(java.lang.String…)方法中通過SPI方式獲取SpringApplicationRunListeners對(duì)象
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //通過SPI方式獲取SpringApplicationRunListener監(jiān)聽器對(duì)象集合 SpringApplicationRunListeners listeners = getRunListeners(args); //啟動(dòng)監(jiān)聽器,傳遞ApplicationStartingEvent事件 listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //environment準(zhǔn)備好之后調(diào)用監(jiān)聽器environmentPrepared方法 //傳遞ApplicationEnvironmentPreparedEvent事件 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); //資源加載之前調(diào)用監(jiān)聽器的contextPrepared方法,傳遞ApplicationContextInitializedEvent事件 //資源加載之后,refresh方法調(diào)用之前調(diào)用監(jiān)聽器的contextLoaded方法,傳遞ApplicationPreparedEvent事件 prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //應(yīng)用程序refresh之后調(diào)用,傳遞ApplicationStartedEvent事件 listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { //應(yīng)用程序啟動(dòng)過程中出現(xiàn)異常調(diào)用failed方法 //傳遞ApplicationFailedEvent事件 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //在應(yīng)用程序run方法運(yùn)行結(jié)束之前調(diào)用,傳遞ApplicationReadyEvent事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; } //通過SPI方式獲取SpringApplicationRunListener接口實(shí)現(xiàn)類,并創(chuàng)建SpringApplicationRunListeners集合類 private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
spring.factories配置文件如下:
# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
到此這篇關(guān)于SpringApplicationRunListener監(jiān)聽器源碼詳解的文章就介紹到這了,更多相關(guān)SpringApplicationRunListener監(jiān)聽器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis批量添加,批量更新之前如何判斷是否已經(jīng)存在
這篇文章主要介紹了mybatis批量添加,批量更新之前如何判斷是否已經(jīng)存在,具有很好的參考價(jià)值,希望對(duì)的有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08生成8位隨機(jī)不重復(fù)的數(shù)字編號(hào)的方法
生成隨機(jī)不重復(fù)的數(shù)字編號(hào)在某些情況下也會(huì)用到,本文以生成8位隨機(jī)不重復(fù)的數(shù)字編號(hào)為例與大家分享下具體的實(shí)現(xiàn)過程,感興趣的朋友可以參考下2013-09-09Springboot簡(jiǎn)單熱部署實(shí)現(xiàn)步驟解析
這篇文章主要介紹了Springboot簡(jiǎn)單熱部署實(shí)現(xiàn)步驟解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12Spring中的@ExceptionHandler注解詳解與應(yīng)用示例
本文詳細(xì)介紹了Spring框架中的@ExceptionHandler注解的用法,包括基本用法、全局異常處理、結(jié)合@ResponseStatus注解以及返回值類型,通過示例展示了如何使用@ExceptionHandler注解處理不同類型的異常,并提供定制化的異常處理響應(yīng),需要的朋友可以參考下2024-11-11spring boot動(dòng)態(tài)切換數(shù)據(jù)源的實(shí)現(xiàn)
這篇文章主要介紹了spring boot動(dòng)態(tài)切換數(shù)據(jù)源的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01