ApplicationListener、SpringApplicationRunListeners、SpringApplicationRunListener的關係:html
經過上面的3個特色能夠看出SpringApplicationRunListener就是一個ApplicationListener的代理。springboot啓動的幾個主要過程的監聽通知都是經過他來進行回調。spring
從命名咱們就能夠知道它是一個監聽者,那縱觀整個啓動流程咱們會發現,它實際上是用來在整個啓動流程中接收不一樣執行點事件通知的監聽者,SpringApplicationRunListener接口規定了SpringBoot的生命週期,在各個生命週期廣播相應的事件,調用實際的ApplicationListener類。springboot
源碼以下:app
public interface SpringApplicationRunListener { //剛執行run方法時 void started(); //環境創建好時候 void environmentPrepared(ConfigurableEnvironment environment); //上下文創建好的時候 void contextPrepared(ConfigurableApplicationContext context); //上下文載入配置時候 void contextLoaded(ConfigurableApplicationContext context); //上下文刷新完成後,run方法執行完以前 void finished(ConfigurableApplicationContext context, Throwable exception); }
它定義了5個步驟:框架
EventPublishingRunListener類 實現了SpringApplicationRunListener,它具備廣播事件的功能。ide
構造函數函數
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered { private final SpringApplication application; private final String[] args; private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args;
//新創建廣播器 this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } //...
從上面代碼能夠看出,它使用了Spring廣播器SimpleApplicationEventMulticaster。它把監聽的過程封裝成了SpringApplicationEvent事件並讓內部屬性(屬性名爲multicaster)ApplicationEventMulticaster接口的實現類SimpleApplicationEventMulticaster廣播出去,廣播出去的事件對象會被SpringApplication中的listeners屬性進行處理。源碼分析
initialMulticaster是在構造函數中初始化的,見上面的代碼片斷。post
源碼以下:this
@Override public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } @Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } }
和invokeListener()方法,其參數是ApplicationListener和ApplicationEvent
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); } }
首先看下starting方法:
public void starting() { this.initialMulticaster .multicastEvent(new ApplicationStartedEvent(this.application, this.args)); }
ApplicationStartingEvent構造方法中傳遞了一個SpringApplication對象和args參數。一直傳遞到了父類EventObject,將SpringApplication對象存放在source變量中。
EventObject類結構。getSource()方法獲得的就是SpringApplication對象。
因此說SpringApplicationRunListener和ApplicationListener之間的關係是經過ApplicationEventMulticaster廣播出去的SpringApplicationEvent所聯繫起來的。更多的spring事件知識見《ApplicationEvent事件機制源碼分析》
對於開發者來講,基本沒有什麼常見的場景要求咱們必須實現一個自定義的SpringApplicationRunListener,即便是SpringBoot中也只默認實現了一個org.springframework.boot.context.eventEventPublishingRunListener
, 用來在SpringBoot的整個啓動流程中的不一樣時間點發布不一樣類型的應用事件(SpringApplicationEvent)。那些對這些應用事件感興趣的ApplicationListener能夠接受並處理(這也解釋了爲何在SpringApplication實例化的時候加載了一批ApplicationListener,但在run方法執行的過程當中並無被使用)。
若是咱們真的在實際場景中自定義實現SpringApplicationRunListener,有一個點須要注意:任何一個SpringApplicationRunListener實現類的構造方法都須要有兩個構造參數,一個參數的類型就是咱們的org.springframework.boot.SpringApplication,另一個參數就是args參數列表的String[]:
package com.dxz.controller; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationRunListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; public class SampleSpringApplicationRunListener implements SpringApplicationRunListener { private final SpringApplication application; private final String[] args; public SampleSpringApplicationRunListener(SpringApplication sa, String[] args) { this.application = sa; this.args = args; } @Override public void starting() { System.out.println("自定義starting"); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { System.out.println("自定義environmentPrepared"); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("自定義contextPrepared"); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("自定義contextLoaded"); } @Override public void finished(ConfigurableApplicationContext context, Throwable exception) { System.out.println("自定義finished"); } }
接着,咱們還要知足SpringFactoriesLoader的約定,在當前SpringBoot項目的classpath下新建META-INF目錄,並在該目錄下新建spring.fatories文件,文件內容以下:
org.springframework.boot.SpringApplicationRunListener=\ com.dxz.SampleSpringApplicationRunListener