SpringBoot擴展點之一:SpringApplicationRunListener

三種監聽器的關係

ApplicationListener、SpringApplicationRunListeners、SpringApplicationRunListener的關係:html

  • SpringApplicationRunListeners類和SpringApplicationRunListener類是SpringBoot中新增的類。ApplicationListener是spring中框架的類。
  • 在SpringBoot(SpringApplication類)中,使用SpringApplicationRunListeners、SpringApplicationRunListener來間接調用ApplicationListener。
  • SpringApplicationRunListeners是SpringApplicationRunListener的封裝,SpringApplicationRunListeners中包含多個SpringApplicationRunListener,是爲了批量執行的封裝,SpringApplicationRunListeners與SpringApplicationRunListener生命週期相同,調用每一個週期的各個SpringApplicationRunListener。而後廣播相應的事件到Spring框架的ApplicationListener。

經過上面的3個特色能夠看出SpringApplicationRunListener就是一個ApplicationListener的代理。springboot啓動的幾個主要過程的監聽通知都是經過他來進行回調。spring

SpringApplicationRunListener

從命名咱們就能夠知道它是一個監聽者,那縱觀整個啓動流程咱們會發現,它實際上是用來在整個啓動流程中接收不一樣執行點事件通知的監聽者,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個步驟:框架

  1.   started(run方法執行的時候立馬執行;對應事件的類型是ApplicationStartedEvent):通知監聽器,SpringBoot開始執行
  2.   environmentPrepared(ApplicationContext建立以前而且環境信息準備好的時候調用;對應事件的類型是ApplicationEnvironmentPreparedEvent):通知監聽器,Environment準備完成
  3.   contextPrepared(ApplicationContext建立好而且在source加載以前調用一次;沒有具體的對應事件):通知監聽器,ApplicationContext已經建立並初始化完成
  4.   contextLoaded(ApplicationContext建立並加載以後並在refresh以前調用;對應事件的類型是ApplicationPreparedEvent):通知監聽器,ApplicationContext已經完成IoC配置價值
  5.   finished(run方法結束以前調用;對應事件的類型是ApplicationReadyEvent或ApplicationFailedEvent):通知監聽器,SpringBoot啓動完成

實現類 EventPublishingRunListener類

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屬性進行處理。源碼分析

EventPublishingRunListener的initialMulticaster成員變量SimpleApplicationEventMulticaster,以及它的multicastEvent()和invokeListener()方法

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);
        }
    }

EventPublishingRunListener的5個方法:

首先看下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
相關文章
相關標籤/搜索