「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

轉載:https://mp.weixin.qq.com/s/mB8pN0o2j08Kq8zXXPCFZQ

生命週期和事件監聽


一個應用的啟動過程和關閉過程是歸屬到“生命週期”這個概念的範疇。
典型的設計是在啟動和關閉過程中會觸發一系列的“事件”,我們只要監聽這些事件,就能參與到這個過程中來。
要想監聽事件,首先得有事件監聽器,就是常說的Listener。下面就是Spring提供的監聽器,如下圖01:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程


按規定所有的監聽器都要繼承Java提供的EventListener接口,這個接口是一個空的marker接口,其實就是標識一下。
事件一般都有多個,一般也有兩種常用解決方法:
要麼定義多個監聽器接口,一個事件一個接口。
要麼一個接口裡定義多個方法,一個事件一個方法。
可惜的是,這兩種方法Spring都沒有采用,仍然只用了一個接口一個方法,那它是如何實現的呢?
相信大家已經看到,監聽器接口有一個泛型參數,沒錯,就是根據泛型參數的不同來區分不同事件的。
這個泛型參數就是事件對象,按規定所有的事件對象都要繼承Java提供的EventObject類,如下圖02:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

Java提供這個類除了有標識作用外,還和事件源有關。任何事件都會有一個觸發者,它就是事件源。可以認為是事件的起源或來源。
既然所有事件都有,乾脆提升到頂級父類裡算了。如下圖03:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

不同的事件,含義完全不同,所以差別很大,因此,通常一種事件會有屬於自己的一種事件對象。
我們只需要看下事件對象有多少種,就能知道事件有多少種。這種判斷方式一般都沒有問題。


下面就是和SpringBoot啟動有關的所有事件對象類型,如下圖04:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

一共有七種事件對象,除去一種是處理失敗用的,還剩六種。也就是說我們可以通過六個事件參與到SpringBoot應用的啟動中去。
實現事件監聽器接口
監聽器就是接口,我們首先要實現這些接口,加入處理邏輯。然後把它們添加到應用中去就行了。


有六種事件對象,我們需要定義六個實現類。
事件對象為ApplicationStartingEvent,如下圖05:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

事件對象為ApplicationEnvironmentPreparedEvent,如下圖06:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

事件對象為ApplicationContextInitializedEvent,如下圖07:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

事件對象為ApplicationPreparedEvent,如下圖08:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

事件對象為ApplicationStartedEvent,如下圖09:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

事件對象為ApplicationReadyEvent,如下圖10:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

把這個六個實現類添加到SpringBoot應用中,如下圖11:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

實現Runner接口
SpringBoot提供了兩個Runner接口,如下圖1213:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

這兩個接口主要用於滿足那種應用剛啟動好後就需要立馬被執行的需求。如定時任務。
我們也來實現下這兩個接口,如下圖1415:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

有一點需要注意的是,這兩個接口的實現類需要作為bean註冊到容器中去。
實現Spring容器初始化接口
如果我們需要對Spring容器進行一些自定義的初始化,可以實現這個接口,如下圖16:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

這個接口的泛型參數其實就是容器對象。
我們也來實現下這個接口,如下圖1718:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

我們可以多次實現這個接口,需要排序的話可以使用@Order註解或實現Ordered接口。
然後把這些實現類添加到SpringBoot應用中去,如下圖19:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

啟動應用,觀察事件觸發的次序
啟動後首先觸發啟動事件,如下圖20:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

接著要做的就是確認環境,創建Environment,然後觸發事件,表明環境已經OK了。如下圖21:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

然後根據環境創建Spring容器對象,創建好後執行自定義容器初始化,如下圖22:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

初始化完成後,觸發事件,表明容器就已經準備好了,如下圖23:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

容器OK之後,就會加載資源(主要是註冊bean定義),加載完成後,就會觸發事件,如下圖24:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

接著Spring容器就會進行refresh,refresh完成之後,其實Spring容器就已經成功啟動好了。
這時會觸發事件,如下圖25:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

容器啟動好後,立馬就會執行Runner,如下圖26:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

Runner執行完後,SpringBoot應用就真正啟動好了,進入了正常運行狀態。
這時會觸發最後一個事件,如下圖27:

「玩轉SpringBoot」通過事件機制參與SpringBoot應用的啟動過程

我們可以根據需要,在對應的事件裡完成自己的需求。


分享到:


相關文章: