Spring Event
Spring 應用程式事件允許我們傳送和接收特定應用程式事件,我們可以根據需要處理這些事件。事件用於在鬆散耦合的元件之間交換資訊。由於釋出者和訂閱者之間沒有直接耦合,因此可以在不影響釋出者的情況下修改訂閱者,反之亦然。 其實就是觀察者模式,我看到一個不錯的例子描述觀察者模式的概念。 Ex.在年代較早以前,去銀行臨櫃領現大家都是需要一個一個排隊,大排長龍等待櫃台處理,但是當出現了叫號機,來銀行領現的人都會先去取號等待櫃檯叫號,在等待叫號的期間可以先去處理自己的事情。 叫號機,相當於事件發布器(事件註冊中心) 客戶,相當於事件源 櫃檯,相當於一個事件監聽器 想當而然 Spring 不想放過這麼好的設計模式。
如上所述,面向事件的編程(也稱作事件驅動編程)是基於對消息信號的反應的編程。 面向事件編程需要滿三個條件:
事件源(ApplicationEvent):消息的源頭,如點擊一個按鈕、訪問某個頁面、新增一條數據等。
事件註冊中心(ApplicationEventPublisher):事件註冊中心用於存儲和發布事件。
事件監聽器(ApplicationListener):用於接收特定的消息,並作出對應的反應。
簡單實作
Event
@Getter
@Setter
public class DemoEvent extends ApplicationEvent {
private Long id;
private String message;
public DemoEvent(Object source, Long id, String message) {
super(source);
this.id = id;
this.message = message;
}
}
Listener
public class DemoListener {
@EventListener
public void firstEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> firstEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
Publisher
@Component
public class DemoPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
public void testEvent() {
applicationEventPublisher.publishEvent(new DemoEvent("DemoEvent", 1l, "Text123456"));
}
}
Controller
@RestController
@RequestMapping(value = "/event")
public class EventController {
@Autowired
DemoPublisher demoPublisher;
@GetMapping("/")
public ResponseEntity testEventApi() {
demoPublisher.testEvent();
return ResponseEntity.ok(JSONResult.createResult(SuccessCodeMsg.COMMON_OK));
}
}
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646215660237
訊息:1:Text123456
同時有多個Listener
Listener
@Component
public class DemoListener {
@EventListener
public void secondEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> secondEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void otherEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> otherEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void firstEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> firstEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
output
>>>>>>>>> secondEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216147911
訊息:1:Text123456
自訂排序Listener執行順序 ( @order)
Listener
@Component
public class DemoListener {
@Order(1)
@EventListener
public void secondEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> secondEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@Order
@EventListener
public void otherEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> otherEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@Order(2)
@EventListener
public void firstEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> firstEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
output
>>>>>>>>> secondEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216288988
訊息:1:Text123456
Default 為同步處理
經Postman 執行時間統計 原先沒有Sleep -> 執行時間 358ms 加上Thread sleep -> 執行時間 3.31s
Listener
@Component
public class DemoListener {
@EventListener
public void secondEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> secondEvent");
for (int i = 0; i < 3; i++) {
try {
System.out.println(">>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void otherEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> otherEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void firstEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> firstEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
output
>>>>>>>>> secondEvent
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>Sleeping ~~ >>>>>>>>>>>>>>>>>>>>>>>>>>>>
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456
>>>>>>>>> firstEvent
收到了:DemoEvent訊息;時間:1646216488728
訊息:1:Text123456
修改為非同步
Listener
@Async
@Component
public class DemoListener {
@EventListener
public void secondEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> secondEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void otherEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> otherEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
@EventListener
public void firstEvent(DemoEvent demoEvent) {
System.out.println(">>>>>>>>> firstEvent");
System.out.println("收到了:" + demoEvent.getSource() + "訊息;時間:" + demoEvent.getTimestamp());
System.out.println("訊息:" + demoEvent.getId() + ":" + demoEvent.getMessage());
}
}
output
>>>>>>>>> secondEvent
>>>>>>>>> firstEvent
>>>>>>>>> otherEvent
收到了:DemoEvent訊息;時間:1646216104512
收到了:DemoEvent訊息;時間:1646216104512
收到了:DemoEvent訊息;時間:1646216104512
訊息:1:Text123456
訊息:1:Text123456
訊息:1:Text123456
參考網站:
Last updated