前言: 事件監聽模型是一種常用的設計模式,在springboot 中我們如何實現呢?
首先我們要理解事件監聽中需要的幾個角色
- 事件發布者 (即事件源)
- 事件監聽者
- 事件本身
廢話不多說直接上代碼
定義事件本身
事件本身需要繼承ApplicationEvent
package com.yxd;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationEvent;
public class DemoEvent extends ApplicationEvent{
private String type;
private List<Map> msg;
public DemoEvent(Object object, String type ,List<Map> msg) {
super(object);
this.msg = msg;
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Map> getMsg() {
return msg;
}
public void setMsg(List<Map> msg) {
this.msg = msg;
}
}
如圖:

定義事件源
事件源需要注入 **ApplicationContext **
package com.yxd;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext;
public void publish(DemoEvent event) {
applicationContext.publishEvent(event);
}
}
定義監聽者
監聽者有兩種實現
一、需要實現 ApplicationListener
package com.yxd;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class DemoListener1 implements ApplicationListener<DemoEvent> {
@Override
public void onApplicationEvent(DemoEvent event) {
List<Map> msg = event.getMsg();
String type = event.getType();
System.out.println(" listener1接收到了 publisher 發送的消息 , 時間 "+ Time.getTime());
System.out.println("listener1 : 類型 :" + type +", 消息內容: " + msg + ", 消息處理完畢! "+ Time.getTime());
}
}
二、使用 @EventListener 注解
package com.yxd;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class DemoListener2 {
@EventListener
public void onDemoEvent(DemoEvent demoEvent) {
System.out.println(" listener2 通過注解接收到了 publisher 發送的消息 , 時間 "+ Time.getTime());
List<Map> msg = demoEvent.getMsg();
String type = demoEvent.getType();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("listener2 : 類型 :" + type +", 消息內容: " + msg + ", 消息處理完畢! "+ Time.getTime());
}
}
此處我們還需要注意一點,此處多個監聽是同步執行的(阻塞),一般情況下我們發布一個事件,是不關心誰來處理,以及處理結果的,所以我們還需要加上異步的注解
package com.yxd;
import java.util.List;
import java.util.Map;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class DemoListener3 implements ApplicationListener<DemoEvent> {
@Override
@Async
public void onApplicationEvent(DemoEvent event) {
System.out.println(" listener3 接收到了 publisher 發送的消息 , 時間 "+ Time.getTime());
List<Map> msg = event.getMsg();
String type = event.getType();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("listener3 異步執行:類型 :" + type +", 消息內容: " + msg+ ", 消息處理完畢! "+ Time.getTime());
}
}
測試
package com.yxd;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@EnableAsync
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Autowired
DemoPublisher demoPublisher;
@RequestMapping("testListener")
public String testListener() {
ArrayList<Map> list = new ArrayList<>();
HashMap<String, String> m1 = new HashMap<>();
m1.put("1", "2");
HashMap<String, String> m2 = new HashMap<>();
m2.put("3", "4");
HashMap<String, String> m3 = new HashMap<>();
m3.put("5", "6");
list.add(m1);
list.add(m2);
list.add(m3);
System.out.println("開始發布消息: " + Time.getTime());
demoPublisher.publish(new DemoEvent(this,"測試消息",list));
System.out.println("消息發布結束: " + Time.getTime());
return "消息發布成功";
}
}
我們訪問接口


三個監聽者都得到了消息。。
但是 listener2 通過注解 先得到了消息,延時2秒后,listener1 才得到消息,listener1 處理完后,主線程繼續執行,同時listener3 開始接收到消息,開啟了一個異步任務,3秒后執行結束
項目結構

最后附上Time類
package com.yxd;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Time {
public static String getTime() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
}
