之前在介紹了在spring-boot啟動過程中調用runner的原理,今天我們介紹另外一種可以實現相似功能的機制:spring-boot的Listener機制。
通過注冊Listener,可以實現對於spring-boot整個生命周期各個狀態變化進行監聽,然后執行相應的業務代碼。我們只需要監聽其中幾個啟動狀態就能夠實現runner一樣的功能了。
如何使用Spring Boot Listener
要想在spring-boot工程中加入自己實現的Listener,只需要完成一下兩步動作:
- 實現SpringApplicationRunListener接口
- 在spring.factories文件中添加上相應的配置
樣例代碼:
SpringApplicationRunListener實現
spring.factories中的配置
運行結果:
從運行結果我們可以看出:
- 各個狀態回調的順序為:starting->environmentPrepared->contextPrepared->contextLoaded->started->running,再加上一個啟動出錯時的回調failed
- 每一個狀態的回調對應的是spring-boot程序在啟動時的不同的階段,可以利用的spring-boot資源也是不一樣的,比如starting狀態就無法利用任何spring-boot相關的功能,因為這個時候spring-boot還沒有進行任何實際的初始化。
Spring Boot Listener的實現原理
Listener的原理可以總結為:
- 加載SpringApplicationRunListener接口的實現類
- 在spring-boot各個啟動階段調用相應的Listener接口
首先我們來看看SpringApplicationRunListener接口的實現類是怎么被加載起來的。要向了解Listener是如何被加載的,就需要先知道Spring的SPI機制(spring.factories機制),這個我將會在另外一篇文章中介紹。
進入SpringApplication的run方法,我們可以看到如下的一段代碼:
加載Listener
在這里就是調用了加載Listener的方法,最終會走到如下的代碼中去
在這個方法中主要做了三件事情:
- 利用spring.factories的機制獲取了所有SpringApplicationRunListener實現類的類名。
- 根據查找到的類名進行實例化,使用的是帶有SpringApplication和String[]兩個參數的構造方法。
- 這些SpringApplicationRunListener實例按照order進行排序。
接下來我們再看看Listener是如何被調用的。
調用starting
在Listener被加載完成以后就立馬調用starting方法了,這個時候spring-boot實際什么都沒有初始化,所以無法使用任何的spring-boot特性。
調用environmentPrepared
調用environmentPrepared
調用contextPrepared和contextLoaded
接下來就會進行context的初始化,在完成context的准備工作后就會調用contextPrepared方法,在完成整個context的初始化工作后就會調用contextLoaded。
started和running都是在run方法中被直接調用的,srping-boot的runner就是在他們之間被調用的。
整個啟動過程都是被try-catch包裹着的,任何異常都會進入handleRunFailure方法,在這個方法中會調用Listener的failed方法。