SpringBoot 事件機制的兩種消費姿勢
藉助 Spring 可以非常簡單的實現事件監聽機制,本文簡單介紹下面向接口與註解監聽的兩種姿勢
公衆號
SpringBoot 事件機制的兩種消費姿勢 [1]
I. 項目環境
本項目藉助SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
進行開發
爲了後面的發佈事件驗證,起一個 web 服務
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
II. 事件機制
1. 事件對象
在 Spring 中,所有的事件需要繼承自ApplicationEvent
,一個最基礎的MsgEvent
如下
public class MsgEvent extends ApplicationEvent {
private String msg;
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public MsgEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
@Override
public String toString() {
return "MsgEvent{" +
"msg='" + msg + '\'' +
'}';
}
}
2. 接口方式消費
消費事件有兩種方式,接口的聲明,主要是實現ApplicationListener
接口;注意需要將 listener 聲明爲 Spring 的 bean 對象
@Service
public class MsgEventListener implements ApplicationListener<MsgEvent> {
@Override
public void onApplicationEvent(MsgEvent event) {
System.out.println("receive msg event: " + event);
}
}
3. 註解方式消費
實現接口需要新建實現類,更簡單的方法是直接在消費方法上加一個註解@EventListener
@EventListener(MsgEvent.class)
public void consumer(MsgEvent msgEvent) {
System.out.println("receive msg by @anno: " + msgEvent);
}
這個註解,支持根據 Event 參數類型進行匹配,即上面的實例中,方法上直接加@EventListener
不指定圓括號內部的也沒關係
4. 發佈事件
前面是消費事件,消費的前提是有事件產生,在 Spring 中,發佈事件主要需要藉助ApplicationContext
來實現
@Service
public class MsgPublisher implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void publish(String msg) {
applicationContext.publishEvent(new MsgEvent(this, msg));
}
}
5. 測試
一個簡單的測試 demo
@RestController
public class IndexController {
@Autowired
private MsgPublisher msgPublisher;
@GetMapping(path = "pub")
public String publish(String msg) {
msgPublisher.publish(msg);
return "ok";
}
}
訪問: curl http://localhost:8082/pub?msg=一灰灰blog
輸出日誌:
receive msg by @anno: MsgEvent{msg='一灰灰blog'}
receive msg event: MsgEvent{msg='一灰灰blog'}
上面這個測試兩種消費方式都可以成功,但是,在實測的過程中發現一種 case,註解消費方式不生效,測試姿勢如下
@SpringBootApplication
public class Application {
public Application(MsgPublisher msgPublisher) {
msgPublisher.publish("一灰灰blog");
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
直接在啓動類的構造方法中發佈事件,發現接口方式可以接收事件,但是註解方式不生效,why?
在 stockoverstack 上有個相似的問題 https://stackoverflow.com/questions/38487474/springboot-eventlistener-dont-receive-events[2],這裏主要提了一個觀點
- 發佈消息比事件消費註冊的要早
那麼是這個原因麼?靜待下次源碼分析
II. 其他
0. 項目
-
工程:https://github.com/liuyueyi/spring-boot-demo[3]
-
源碼:https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/012-context-listener/[4]
1. 一灰灰 Blog
盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激
下面一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
-
一灰灰 Blog 個人博客 https://blog.hhui.top[5]
-
一灰灰 Blog-Spring 專題博客 http://spring.hhui.top[6]
參考資料
[1]
SpringBoot 事件機制的兩種消費姿勢: https://spring.hhui.top/spring-blog/2021/04/29/210429-SpringBoot%E4%BA%8B%E4%BB%B6%E6%9C%BA%E5%88%B6%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%B6%88%E8%B4%B9%E5%A7%BF%E5%8A%BF/
[2]
https://stackoverflow.com/questions/38487474/springboot-eventlistener-dont-receive-events: https://stackoverflow.com/questions/38487474/springboot-eventlistener-dont-receive-events
[3]
https://github.com/liuyueyi/spring-boot-demo: https://github.com/liuyueyi/spring-boot-demo
[4]
https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/012-context-listener/: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/012-context-listener/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/rxBnI7S48voo8dzfOL3DbQ