SpringApplicationRunListener監(jiān)聽器源碼詳解
前言
springboot提供了兩個類SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架還提供了一個ApplicationListener接口,那么這幾個類或接口的關(guān)系又是如何呢?
首先SpringApplicationRunListeners類是SpringApplicationRunListener接口的代理類,可以批量調(diào)用SpringApplicationRunListener接口方法,SpringApplicationRunListener接口只有一個實現(xiàn)類EventPublishingRunListener,其有一個屬性SimpleApplicationEventMulticaster,SimpleApplicationEventMulticaster即是一個ApplicationListener監(jiān)聽器接口的代理實現(xiàn)類,可以批量的執(zhí)行監(jiān)聽器的onApplicationEvent方法。
1.SpringApplicationRunListener接口源碼
SpringApplicationRunListener是對org.springframework.boot.SpringApplication類的run方法進行監(jiān)聽,SpringApplicationRunListener實現(xiàn)類是通過SpringFactoriesLoader類加載(即springboot SPI);并且需要聲明一個包含SpringApplication實例及String[]的參數(shù)構(gòu)造方法。
public interface SpringApplicationRunListener { /** * 當run方法第一次啟動時立即調(diào)用,可用于非常早期的初始化 */ default void starting() { } /** * 在ApplicationContext創(chuàng)建之前,一旦環(huán)境environment準備好就調(diào)用。 * @param environment the environment */ default void environmentPrepared(ConfigurableEnvironment environment) { } /** * 在資源(可以理解為配置主類)被加載完成之前,一旦ApplicationContext被創(chuàng)建并準備好就立馬調(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)用程序已啟動,但是CommandLineRunner和ApplicationRunner尚未調(diào)用。 * @param context the application context. * @since 2.0.0 */ default void started(ConfigurableApplicationContext context) { } /** * 當ApplicationContext已經(jīng)refresh且所有的CommandLineRunner和ApplicationRunner都已被調(diào)用時,在run方法完成之前立即調(diào)用。 * @param context the application context. * @since 2.0.0 */ default void running(ConfigurableApplicationContext context) { } /** * 在運行應(yīng)用程序時發(fā)生故障時調(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接口唯一實現(xiàn)類EventPublishingRunListener
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { //啟動類實例對象 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)聽器助手屬性對象中 for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } }
其中application.getListeners()獲取通過SPI方式定義的所有ApplicationListener監(jiān)聽器接口定義的監(jiān)聽器類,其初始化是在SpringApplication類中通過構(gòu)造函數(shù)的方式,如下:
//監(jiān)聽器對象集合 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接口實現(xiàn)類集合類SpringApplicationRunListeners
class SpringApplicationRunListeners { private final Log log; //存儲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對象
org.springframework.boot.SpringApplication#run(java.lang.String…)方法中通過SPI方式獲取SpringApplicationRunListeners對象
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //通過SPI方式獲取SpringApplicationRunListener監(jiān)聽器對象集合 SpringApplicationRunListeners listeners = getRunListeners(args); //啟動監(jiān)聽器,傳遞ApplicationStartingEvent事件 listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //environment準備好之后調(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)用程序啟動過程中出現(xiàn)異常調(diào)用failed方法 //傳遞ApplicationFailedEvent事件 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //在應(yīng)用程序run方法運行結(jié)束之前調(diào)用,傳遞ApplicationReadyEvent事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; } //通過SPI方式獲取SpringApplicationRunListener接口實現(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis批量添加,批量更新之前如何判斷是否已經(jīng)存在
這篇文章主要介紹了mybatis批量添加,批量更新之前如何判斷是否已經(jīng)存在,具有很好的參考價值,希望對的有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08Spring中的@ExceptionHandler注解詳解與應(yīng)用示例
本文詳細介紹了Spring框架中的@ExceptionHandler注解的用法,包括基本用法、全局異常處理、結(jié)合@ResponseStatus注解以及返回值類型,通過示例展示了如何使用@ExceptionHandler注解處理不同類型的異常,并提供定制化的異常處理響應(yīng),需要的朋友可以參考下2024-11-11spring boot動態(tài)切換數(shù)據(jù)源的實現(xiàn)
這篇文章主要介紹了spring boot動態(tài)切換數(shù)據(jù)源的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01