Spring Boot應用程式事件教程 - reflectoring
如果要“監聽”事件,我們可以在事件發生源處編寫“監聽器”來監聽事件,但會將事件源與偵聽器的邏輯緊密耦合。我們可以根據需要動態註冊和登出某些事件的偵聽器。對於同一事件,我們也可以有多個偵聽器。本教程概述瞭如何釋出和監聽自定義事件,並解釋了Spring Boot的內建事件。
事件與直接方法呼叫
事件和直接方法呼叫都適合於不同的情況。對於方法呼叫,這就像斷言一樣,無論傳送和接收模組的狀態如何,他們都需要知道此事件的發生。
另一方面,對於事件,我們只是說發生了一個事件,並且通知了哪些模組不是我們關心的問題。當我們想將處理傳遞給另一個執行緒時,最好使用事件(例如:在完成某些任務時傳送電子郵件)。同樣,事件對於測試驅動的開發非常有用。
事件用於在松耦合的元件之間交換資訊。由於釋出者和訂閱者之間沒有直接耦合,因此我們可以修改訂閱者而不影響釋出者,反之亦然。讓我們看看如何在Spring Boot應用程式中建立,釋出和收聽自定義事件。
1. 建立一個 ApplicationEvent
我們可以使用Spring Framework的事件釋出機制來發布應用程式事件。
讓我們建立一個UserCreatedEvent透過擴充套件呼叫的自定義事件ApplicationEvent:
class UserCreatedEvent extends ApplicationEvent { private String name; UserCreatedEvent(Object source, String name) { super(source); this.name = name; } ... } |
source物件是事件發生時可以初始化和傳遞的引數,傳遞道super()方法。
從Spring 4.2開始,我們還可以將物件直接釋出為事件,而無需擴充套件ApplicationEvent:
class UserRemovedEvent { private String name; UserRemovedEvent(String name) { this.name = name; } ... } |
2.釋出一個 ApplicationEvent
我們使用ApplicationEventPublisher介面來發布事件:
@Component class Publisher { private final ApplicationEventPublisher publisher; Publisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } void publishEvent(final String name) { // Publishing event created by extending ApplicationEvent publisher.publishEvent(new UserCreatedEvent(this, name)); // Publishing an object as an event publisher.publishEvent(new UserRemovedEvent(name)); } } |
當我們釋出的物件不是ApplicationEvent時,Spring會自動用PayloadApplicationEvent包裝它
3. 監聽事件
現在我們知道如何建立和釋出自定義事件,讓我們看看如何監聽事件。一個事件可以有多個偵聽器根據應用程式需求執行不同的工作。
有兩種定義偵聽器的方法。我們可以使用@EventListener註釋或實現ApplicationListener介面。無論哪種情況,監聽器類都必須由Spring管理。
從Spring 4.1開始,現在可以簡單地註釋託管bean的方法,@EventListener以自動註冊ApplicationListener與該方法的簽名匹配的方法:
@Component class UserRemovedListener { @EventListener ReturnedEvent handleUserRemovedEvent(UserRemovedEvent event) { // handle UserRemovedEvent ... return new ReturnedEvent(); } @EventListener void handleReturnedEvent(ReturnedEvent event) { // handle ReturnedEvent ... } ... } |
啟用註釋驅動的配置時,不需要其他配置。我們的方法可以監聽多個事件,或者如果我們想完全不使用任何引數來定義它,那麼事件型別也可以在註釋本身上指定。範例:@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})。
對於帶有註釋@EventListener的方法的返回型別如定義為非void,Spring會將結果作為新事件釋出給我們。在上面的示例中,ReturnedEvent第一種方法返回的結果將被髮布,然後由第二種方法處理。
如果指定SpEL,Spring僅在某些情況下允許觸發我們的偵聽器condition:
@Component class UserRemovedListener { @EventListener(condition = "event.name eq 'reflectoring'") void handleConditionalListener(UserRemovedEvent event) { // handle UserRemovedEvent } } |
僅當表示式的計算結果為true,或包含以下字串之一時:“true”, “on”, “yes”, 或“1”.方法引數透過其名稱公開。條件表示式還公開了一個引用了raw ApplicationEvent(root.event)和實際方法引數的“根”變數(root.args)
在以上示例中,UserRemovedEvent僅當event.name的值為時'reflectoring',才會觸發偵聽器。
偵聽事件的另一種方法是實現ApplicationListener介面:
@Component class UserCreatedListener implements ApplicationListener<UserCreatedEvent> { @Override public void onApplicationEvent(UserCreatedEvent event) { // handle UserCreatedEvent } } |
只要偵聽器物件在Spring應用程式上下文中註冊,它就會接收事件。當Spring路由一個事件時,它使用偵聽器的簽名來確定它是否與事件匹配。
非同步事件監聽器
預設情況下,spring事件是同步的,這意味著釋出者執行緒將阻塞,直到所有偵聽器都完成對事件的處理為止。
要使事件偵聽器以非同步模式執行,我們要做的就是@Async在該偵聽器上使用註釋:
@Component class AsyncListener { @Async @EventListener void handleAsyncEvent(String event) { // handle event } } |
為了使@Async註釋生效,我們還必須註釋一個@Configuration類,使用@EnableAsync註釋SpringBootApplication類。
上面的程式碼示例還顯示,我們可以將String用作事件。使用風險自負。最好使用特定於我們用例的資料型別,以免與其他事件衝突。
事務繫結事件
Spring允許我們將事件偵聽器繫結到當前事務的某個階段。噹噹前事務的結果對偵聽器很重要時,這使事件可以更靈活地使用。
當我們使用註釋我們的方法時@TransactionalEventListener,我們得到了一個擴充套件的事件監聽器,該監聽器知道事務:
@Component class UserRemovedListener { @TransactionalEventListener(phase=TransactionPhase.AFTER_COMPLETION) void handleAfterUserRemoved(UserRemovedEvent event) { // handle UserRemovedEvent } } |
UserRemovedListener 僅在當前事務完成時才呼叫。
我們可以將偵聽器繫結到事務的以下階段:
- AFTER_COMMIT:成功提交事務後,將處理該事件。如果事件偵聽器僅在當前事務成功時才執行,則可以使用此方法。
- AFTER_COMPLETION:在事務提交或回滾時將處理該事件。例如,我們可以使用它在事務完成後執行清理。
- AFTER_ROLLBACK:交易回滾後,將處理該事件。
- BEFORE_COMMIT:事件將在事務提交之前處理。例如,我們可以使用它來將事務性O / R對映會話重新整理到資料庫。
Spring Boot的應用程式事件
以上是Spring事件,Spring Boot提供了幾個預定義ApplicationEvent的,這些預定義繫結到SpringApplication生命週期。
在ApplicationContext建立之前會觸發一些事件,因此我們無法將這些事件註冊為@Bean。我們可以透過手動新增偵聽器來註冊這些事件的偵聽器:
@SpringBootApplication public class EventsDemoApplication { public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(EventsDemoApplication.class); springApplication.addListeners(new SpringBuiltInEventsListener()); springApplication.run(args); } } |
透過將META-INF/spring.factories檔案新增到我們的專案中,我們還可以註冊偵聽器,而不管如何建立應用的。並透過以下org.springframework.context.ApplicationListener鍵引用偵聽器:
org.springframework.context.ApplicationListener= com.reflectoring.eventdemo.SpringBuiltInEventsListener
class SpringBuiltInEventsListener implements ApplicationListener<SpringApplicationEvent>{ @Override public void onApplicationEvent(SpringApplicationEvent event) { // handle event } } |
一旦確保正確註冊了事件監聽器,我們就可以監聽所有Spring Boot的SpringApplicationEvents。讓我們按照它們應用程式啟動期間的執行順序來看看:
ApplicationStartingEvent
ApplicationStartingEvent在執行開始時但在任何處理之前都會觸發,除了偵聽器和初始化程式的註冊外。
ApplicationEnvironmentPreparedEvent
當Environment在上下文中是可用的,一個ApplicationEnvironmentPreparedEvent被觸發,由於此時Environment將準備就緒,因此我們可以在其他bean使用它之前對其進行檢查和修改。
ApplicationContextInitializedEvent
ApplicationContext已準備就緒時,一個ApplicationContextInitializedEvent觸發,ApplicationContextInitializers被稱為尚未載入bean定義。在bean初始化到Spring容器之前,我們可以使用它執行任務。
ApplicationPreparedEvent
當ApllicationContext準備就緒時,一個ApplicationPreparedEvent時會觸發,但不會重新整理。
在準備好的Environment和bean定義將被載入。
ContextRefreshedEvent
當ApplicationContext重新整理時,ContextRefreshedEvent會觸發。
ContextRefreshedEvent是直接來自Spring,而不是Spring Boot,並不繼承擴充套件SpringApplicationEvent。
WebServerInitializedEvent
如果我們使用的是Web伺服器,WebServerInitializedEvent則在Web伺服器準備就緒後會觸發a。ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分別是servlet和反應式變數。
WebServerInitializedEvent不是繼承擴充套件SpringApplicationEvent。
ApplicationStartedEvent
上下文已被重新整理之後,一個ApplicationStartedEvent觸發,但在任何Spring boot應用程式和命令列執行都被呼叫前。
ApplicationReadyEvent
一個ApplicationReadyEvent觸發時就表示該應用程式已準備好服務請求。
建議此時不要修改內部狀態,因為所有初始化步驟都將完成。
ApplicationFailedEvent
一個ApplicationFailedEvent如果有異常,應用程式無法啟動點火。在啟動期間的任何時間都可能發生這種情況。我們可以使用它來執行一些任務,例如執行指令碼或在啟動失敗時發出通知。
結論
事件被設計為在同一應用程式上下文中在Spring bean之間進行簡單的通訊。從Spring 4.2開始,基礎結構已得到顯著改進,並提供了基於註釋的模型以及釋出任意事件的功能。
您可以在GitHub上找到示例程式碼。
相關文章
- Spring Boot應用程式有哪些功能?Spring Boot
- Spring Boot 應用程式中的 QueryDSLSpring Boot
- Spring Boot + Kotlin + Coroutines應用演示程式Spring BootKotlin
- Spring Boot 應用程式啟動流程分析Spring Boot
- 如何使用Spring Boot和Flyway建立不同資料庫的多租戶應用? - reflectoring.ioSpring Boot資料庫
- 在Spring Boot應用程式中使用Kubernetes ConfigMapSpring Boot
- Spring Boot通過@ConfigurationProperties訪問靜態資料 - reflectoringSpring Boot
- Spring Boot應用程式中的常用註釋列表Spring Boot
- Spring Boot 之事件(Event)Spring Boot事件
- Spring boot應用如何支援httpsSpring BootHTTP
- Spring Boot 之路(一):一個簡單的Spring Boot應用Spring Boot
- spring-boot-route(十八)spring-boot-adtuator監控應用Springboot
- Spring Boot Web應用程式下載Excel檔案 - simplesolutionSpring BootWebExcel
- 響應式程式設計基礎教程:Spring Boot 與 Lettuce 整合程式設計Spring Boot
- Spring Boot 教程 - ElasticsearchSpring BootElasticsearch
- Spring Boot 事件和監聽Spring Boot事件
- Spring Boot(三):Spring Boot中的事件的使用 與Spring Boot啟動流程(Event 事件 和 Listeners監聽器)Spring Boot事件
- 在IntelliJ idea中使用docker除錯Spring Boot應用程式IntelliJIdeaDocker除錯Spring Boot
- Spring Boot應用監控實戰Spring Boot
- 如何預熱Spring Boot應用? - sebsteinSpring Boot
- 使用Spring Boot和Swagger進行API優先開發 - reflectoring.ioSpring BootSwaggerAPI
- Spring Boot2 系列教程(三)理解 Spring BootSpring Boot
- 用Spring Boot顛覆Java應用開發Spring BootJava
- Spring Boot中面向方面程式設計 (AOP)教程Spring Boot程式設計
- 如何在Spring Boot應用程式中啟用GZIP壓縮? | 前端後端Spring Boot前端後端
- Spring Boot 2.x基礎教程:配置後設資料的應用Spring Boot
- Spring Boot和EventStoreDB事件溯源案例Spring Boot事件
- 在Spring Boot應用啟動時如何執行程式碼? -DukesletterSpring Boot行程
- Spring Boot 中 10 行程式碼構建 RESTful 風格應用Spring Boot行程REST
- 設定Jenkins伺服器構建Spring Boot應用程式 - MarcusJenkins伺服器Spring Boot
- 你知道如何自動儲存 Spring Boot 應用程式號嗎Spring Boot
- Spring Boot-Redis教程Spring BootRedis
- Spring Boot Security配置教程Spring Boot
- Spring Boot Admin2.1應用監控Spring Boot
- 如何優雅地停止 Spring Boot 應用?Spring Boot
- Spring Boot 和 Spring Cloud 應用記憶體如何管理?Spring BootCloud記憶體
- spring-boot-plus1.1.0.釋出-整合Spring Boot Admin管理和監控應用Spring Boot
- 如何使用ParcelJS在Spring Boot應用程式中打包前端 - codecentric AG BlogJSSpring Boot前端