一:背景
在開發工作中,會遇到一種場景,做完某一件事情以后,需要廣播一些消息或者通知,告訴其他的模塊進行一些事件處理,一般來說,可以一個一個發送請求去通知,但是有一種更好的方式,那就是事件監聽,事件監聽也是設計模式中發布-訂閱模式、觀察者模式的一種實現。
觀察者模式:簡單的來講就是你在做事情的時候身邊有人在盯着你,當你做的某一件事情是旁邊觀察的人感興趣的事情的時候,他會根據這個事情做一些其他的事,但是盯着你看的人必須要到你這里來登記,否則你無法通知到他(或者說他沒有資格來盯着你做事情)。
對於 Spring 容器的一些事件,可以監聽並且觸發相應的方法。通常的方法有 2 種,ApplicationListener 接口和@EventListener 注解。
二:簡介
要想順利的創建監聽器,並起作用,這個過程中需要這樣幾個角色:
1、事件(event)可以封裝和傳遞監聽器中要處理的參數,如對象或字符串,並作為監聽器中監聽的目標。
2、監聽器(listener)具體根據事件發生的業務處理模塊,這里可以接收處理事件中封裝的對象或字符串。
3、事件發布者(publisher)事件發生的觸發者。
三:ApplicationListener 接口
ApplicationListener 接口的定義如下:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
它是一個泛型接口,泛型的類型必須是 ApplicationEvent 及其子類,只要實現了這個接口,那么當容器有相應的事件觸發時,就能觸發 onApplicationEvent 方法。ApplicationEvent 類的子類有很多,Spring 框架自帶的如下幾個。
使用方法很簡單,就是實現一個 ApplicationListener 接口,並且將加入到容器中就行。
@Component public class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> { // @Override // public void onApplicationEvent(ApplicationEvent event) { // System.out.println("事件觸發:"+event.getClass().getName()); // } @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("事件觸發:"+event.getClass().getName()); } }
可以看到控制台輸出:這樣就觸發了spring默認的一些事件。
事件觸發:org.springframework.boot.context.event.ApplicationStartedEvent
事件觸發:org.springframework.boot.context.event.ApplicationReadyEvent
自定義事件以及監聽
定義事件
首先,我們需要定義一個時間(MyTestEvent),需要繼承Spring的ApplicationEvent
public class MyTestEvent extends ApplicationEvent { private static final long serialVersionUID = 1L; private String msg ; public MyTestEvent(Object source,String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
定義監聽器
需要定義一下監聽器,自己定義的監聽器需要實現ApplicationListener,同時泛型參數要加上自己要監聽的事件Class名,在重寫的方法onApplicationEvent中,添加自己的業務處理:
@Component public class MyNoAnnotationListener implements ApplicationListener<MyTestEvent> { @Override public void onApplicationEvent(MyTestEvent event) { System.out.println("非注解監聽器:" + event.getMsg()); } }
事件發布
有了事件,有了事件監聽者,那么什么時候觸發這個事件呢?每次想讓監聽器收到事件通知的時候,就可以調用一下事件發布的操作。首先在類里自動注入了ApplicationEventPublisher,這個也就是我們的ApplicationCOntext,它實現了這個接口。
@RestController @RequestMapping("testEventController") public class MyTestEventController { @Autowired private ApplicationEventPublisher applicationEventPublisher; @RequestMapping(value = "/testPublishEvent1" ) public void testPublishEvent(){ applicationEventPublisher.publishEvent(new MyTestEvent(this, "我來了")); } }
輸出結果如下圖所示:
非注解監聽器:我來了
四:@EventListener 注解
簡單使用
除了通過實現接口,還可以使用@EventListener 注解,實現對任意的方法都能監聽事件。
在任意方法上標注@EventListener 注解,指定 classes,即需要處理的事件類型,一般就是 ApplicationEven 及其子類,可以設置多項。
@Configuration public class Config { @EventListener(classes = {SpringApplicationEvent.class}) public void listen(SpringApplicationEvent event) { System.out.println("注解事件觸發:" + event.getClass().getName()); } }
啟動項目
可以看到控制台和之前的輸出是一樣的:
注解事件觸發:org.springframework.boot.context.event.ApplicationStartedEvent
注解事件觸發:org.springframework.boot.context.event.ApplicationReadyEvent
自定義事件以及監聽
使用注解的好處是不用每次都去實現ApplicationListener,可以在一個class中定義多個方法,用@EventListener來做方法級別的注解。
和上面類似,事件以及事件發布不需要改變,只要這樣定義監聽器即可。
此時,就可以有一個發布,兩個監聽器監聽到發布的消息了,一個是注解方式,一個是非注解方式
結果:
注解監聽器----1:我來了
非注解監聽器:我來了
總結
上面介紹了@EventListener的原理,其實上面方法里還有一個@TransactionalEventListener注解,其實原理是一模一樣的,只是這個監聽者可以選擇在事務完成后才會被執行,事務執行失敗就不會被執行。
這兩個注解的邏輯是一模一樣的,並且@TransactionalEventListener本身就被標記有@EventListener,
只是最后生成監聽器時所用的工廠不一樣而已。