SpringBoot中@EventListener注解的使用


一:背景
在開發工作中,會遇到一種場景,做完某一件事情以后,需要廣播一些消息或者通知,告訴其他的模塊進行一些事件處理,一般來說,可以一個一個發送請求去通知,但是有一種更好的方式,那就是事件監聽,事件監聽也是設計模式中發布-訂閱模式、觀察者模式的一種實現。
觀察者模式:簡單的來講就是你在做事情的時候身邊有人在盯着你,當你做的某一件事情是旁邊觀察的人感興趣的事情的時候,他會根據這個事情做一些其他的事,但是盯着你看的人必須要到你這里來登記,否則你無法通知到他(或者說他沒有資格來盯着你做事情)。
對於 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,
只是最后生成監聽器時所用的工廠不一樣而已。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM