一、價值
Spring Boot和Spring 事件是SpringApplication整個生命週期重要環節
二、Spring Boot事件發佈
1.切入點
Spring Boot和Spring 事件的觸發發生在SpringApplication運行階段,圍繞run(String…)方法不同階段觸發。run(String…)結合SpringApplication初始化階段完成的相關狀態,進一步完善了運行時所需要準備的資源,隨後啓動Spring應用上下文,在此期間就會伴隨Spring Boot和Spring 事件的觸發
2. 源碼(SpringBoot 2.0和1.0有一定的差別但不大,截圖爲2.0源碼):
3.SpringApplicationRunListeners:
按照源碼邏輯的實現,SpringApplicationRunListeners是有getRunListeners(String[] args)方法創建的,SpringApplicationRunListeners屬於組合模式的實現,重點在其內部關聯SpringApplicationRunListener集合
5.SpringApplicationRunListener:
SpringApplicationRunListener爲Spring Boot應用運行時監聽器,其監聽方法被SpringApplicationRunListeners迭代執行。
監聽方法有:
監聽方法 | 運行時階段說明 | 事件 |
---|---|---|
starting() | Spring應用剛啓動 | ApplicationStartingEvent |
environmentPrepared(ConfigurableEnvironment) | ConfigurableEnvironment準備妥當,允許將其調整 | ApplicationEnvironmentPreparedEvent |
contextPrepared(ConfigurableApplicationContext) | ConfigurableApplicationContext準備妥當,允許將其調整 | 無 |
contextLoaded(ConfigurableApplicationContext) | ConfigurableApplicationContext已裝載,但未啓動 | ApplicationPreparedEvent |
started(ConfigurableApplicationContext) | ConfigurableApplicationContext已啓動,此時Spring Bean已初始化完成 | ApplicationStartedEvent |
running(ConfigurableApplicationContext ) | Spring應用正在運行 | ApplicationReadyEvent |
failed(ConfigurableApplicationContext context, Throwable exception) | Spring應用運行失敗 | ApplicationFailedEvent |
4.SpringApplicationRunListener內建實現
- 結合SpringFactoriesLoader機制,能快速定位到其內建實現:EventPublishingRunListener,而且是唯一實現
- 將SpringApplication初始化階段關聯的ApplicationListener實例列表動態的添加到SimpleApplicationEventMulticaster對象中。SimpleApplicationEventMulticaster源於Spring Framework,從源碼可以看出實現ApplicationEventMulticaster接口,用於發佈Spring應用事件(ApplicationEvent)。因此EventPublishingRunListener實際是作爲Spring Boot事件發佈者
四、Spring 事件發佈
-
ApplicationEventMulticaster註冊ApplicationListener UML如下:
本質上就是將ApplicationEvent與ApplicationListener集合進行關聯,因此AbstractApplicationEventMulticaster#getApplicationListeners(
ApplicationEvent event, ResolvableType eventType)方法返回event關聯ApplicationListener集合。具體可查看源碼 -
ApplicationEventMulticaster事件廣播
主要涉及兩個方法:multicastEvent(ApplicationEvent event)和multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType),兩個這方法均在SimpleApplicationEventMulticaster中實現並且是唯一實現。 -
ApplicationContext事件發佈
從uml文件可以看出ApplicationContext的子接口ConfigurableApplicationContext提供了添加ApplicationListenner實例方法:addApplicationListener(ApplicationListener<?> listener).
故ApplicationContext通過調用publishEvent(ApplicationEvent event)發佈事件 -
Spring 內建事件
事件 | 介紹 | 描述 |
---|---|---|
ContextRefreshedEvent | Spring應用上下文就緒事件 | 當ConfigurableApplicationContext#refresh()方法執行到finishRefresh()方法時,發佈ContextRefreshedEvent。此時Spring應用上下文中bean均已完成初始化,可以通過監聽該事件獲取需要Bean,防止出現Bean提早初始化所帶來的的風險 |
ContextStartedEvent | Spring應用上下文啓動事件(大多數場景基本不會觸發) | AbstractApplicationContext#start()時觸發,同時能回調Lifecycle Bean的生命週期 |
ContextStoppedEvent | Spring應用上下文停止事件(大多數場景基本不會觸發) | AbstractApplicationContext#stop()時觸發,同時能回調Lifecycle Bean的生命週期 |
ContextClosedEvent | Spring應用上下文關閉事件 | ConfigurableApplicationContext#close()時觸發,由子類AbstractApplicationContext實現,執行close()後當前Spring應用上下文完全被銷燬,無法恢復(這和調用stop()有本質的區別) |
5.Spring應用上下文事件ApplicationContextEvent和Spring 內建時間關係如下:
六、run(String…)執行過程中各事件發佈點以及順序(Spring Boot 2.0.8)
序號 | 監聽方法 | 運行時階段說明 | 事件 |
---|---|---|---|
1 | starting() | Spring應用剛啓動 | ApplicationStartingEvent |
2 | environmentPrepared(ConfigurableEnvironment) | ConfigurableEnvironment準備妥當,允許將其調整 | ApplicationEnvironmentPreparedEvent |
3 | prepareContext(…)->contextPrepared(ConfigurableApplicationContext) | ConfigurableApplicationContext準備與裝載 | 無 |
4 | contextLoaded(ConfigurableApplicationContext) | ConfigurableApplicationContext已裝載,但未啓動 | ApplicationPreparedEvent |
5 | refreshContext(context)->AbstractApplicationContext#rrefresh(ApplicationContext)->finishRefresh() | ConfigurableApplicationContext啓動以及Spring Bean初始化,執行完畢後,Spring應用上下文正式進入Spring生命週期,Spring Boot核心特性也隨之啓動例如組件自動裝配、嵌入式容器啓動、Production-Ready特性 | ContextRefreshedEvent |
6 | started(ConfigurableApplicationContext) | ConfigurableApplicationContext已啓動,此時Spring Bean已初始化完成 | ApplicationStartedEvent |
7 | running(ConfigurableApplicationContext ) | Spring應用正在運行 | ApplicationReadyEvent |
8 | failed(ConfigurableApplicationContext context, Throwable exception) | Spring應用運行失敗 | ApplicationFailedEvent |
代碼驗證(Spring Boot 2.0.8)
public static void main(String[] args) {
new SpringApplicationBuilder(Object.class)
.listeners(event ->
System.out.printf("監聽到事件: %s , 事件源 : %s\n"
, event.getClass().getSimpleName(), event.getSource())
)
.web(false)
.run(args)
.close();
}
結果:(注意Spring Boot和Spring 事件源)