詳解SpringBoot實現(xiàn)事件同步與異步監(jiān)聽
簡介
說明
本文用示例介紹SpringBoot中的事件的用法及原理。
事件監(jiān)聽簡述
事件的發(fā)布與監(jiān)聽從屬于觀察者模式;和MQ相比,事件的發(fā)布與監(jiān)聽偏向于處理服務(wù)內(nèi)的某些邏輯。
多個監(jiān)聽器可以監(jiān)聽同一個事件。例如:發(fā)布了事件A,監(jiān)聽器A和監(jiān)聽器B都監(jiān)聽了事件A,則監(jiān)聽器A和B都會進行處理。
同步與異步監(jiān)聽
監(jiān)聽方式 | 特點 | 使用時機 |
---|---|---|
同步監(jiān)聽 | 發(fā)布器線程與監(jiān)聽器線程處于同一線程 | 1.監(jiān)聽邏輯處理較快 2.需要緊接著根據(jù)監(jiān)聽器追蹤業(yè)務(wù)線程 |
異步監(jiān)聽 | 發(fā)布器線程與監(jiān)聽器線程處于不同線程 | 1.監(jiān)聽邏輯處理比較耗時 2.追求響應(yīng)性能 |
事件的順序
可使用實現(xiàn)Ordered接口的方式,調(diào)整監(jiān)聽器順序。
注意:必須是同時實現(xiàn) ApplicationListener<MyEvent>,Ordered這樣的方法才能控制順序。
下邊幾種都是無法控制順序的:
- @Component+@EventListerner+實現(xiàn)Ordered
- 實現(xiàn) ApplicationListener<MyEvent>+@Order
實例
同步監(jiān)聽(無序)
事件
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
監(jiān)聽器
監(jiān)聽器1
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener"); System.out.println("監(jiān)聽器所在線程:" + Thread.currentThread().getName()); System.out.println("事件: " + event); System.out.println("事件的數(shù)據(jù): " + event.getSource()); } }
監(jiān)聽器2
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener2 { @EventListener public void onApplicationEvent(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener2"); System.out.println(" 所在線程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的數(shù)據(jù):" + event.getSource()); } }
發(fā)布器
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("發(fā)布器所在線程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
測試
寫一個Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
啟動后,訪問:http://localhost:8080/test1
后端輸出:
發(fā)布器所在線程:http-nio-8080-exec-1
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
監(jiān)聽器: MyListener2
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
可以發(fā)現(xiàn),所有監(jiān)聽器和發(fā)布器都在同一個線程。
同步監(jiān)聽(有序)
事件
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
監(jiān)聽器
監(jiān)聽器1
package com.example.event; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component public class MyListener implements ApplicationListener<MyEvent>, Ordered { @Override public void onApplicationEvent(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener"); System.out.println(" 所在線程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的數(shù)據(jù):" + event.getSource()); } @Override public int getOrder() { return 2; } }
監(jiān)聽器2
package com.example.event; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component public class MyListener2 implements ApplicationListener<MyEvent>, Ordered { public void onApplicationEvent(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener2"); System.out.println(" 所在線程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的數(shù)據(jù):" + event.getSource()); } @Override public int getOrder() { return 1; } }
發(fā)布器
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("發(fā)布器所在線程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
測試
寫一個Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
啟動后,訪問:http://localhost:8080/test1
后端輸出:
發(fā)布器所在線程:http-nio-8080-exec-1
監(jiān)聽器: MyListener2
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
如果將監(jiān)聽器的實現(xiàn)的Ordered順序顛倒,則輸出結(jié)果如下:
發(fā)布器所在線程:http-nio-8080-exec-1
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
監(jiān)聽器: MyListener2
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
異步監(jiān)聽(無序)
方法:
- 開啟異步監(jiān)聽
- 在監(jiān)聽器上加@Async(此監(jiān)聽器必須是@Component方法注冊的)
事件
package com.example.event; import org.springframework.context.ApplicationEvent; public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } }
同步監(jiān)聽器
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class MyListener { @EventListener public void abc(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener"); System.out.println(" 所在線程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的數(shù)據(jù):" + event.getSource()); } }
異步監(jiān)聽器
package com.example.event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component @Async public class MyListener2 { @EventListener public void onApplicationEvent(MyEvent event) { System.out.println("監(jiān)聽器: " + "MyListener2"); System.out.println(" 所在線程: " + Thread.currentThread().getName()); System.out.println(" 事件: " + event); System.out.println(" 事件的數(shù)據(jù):" + event.getSource()); } }
發(fā)布器
package com.example.event; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class MyPublisher { @Autowired ApplicationContext applicationContext; public void myPublish(String message) { System.out.println("發(fā)布器所在線程:" + Thread.currentThread().getName()); applicationContext.publishEvent(new MyEvent(message)); } }
啟動類
package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableAsync public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
測試
寫一個Controller
package com.example.controller; import com.example.event.MyPublisher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @Autowired MyPublisher myPublisher; @GetMapping("/test1") public String test1() { myPublisher.myPublish("Hello"); return "test1 success"; } }
啟動后,訪問:http://localhost:8080/test1
后端輸出:
發(fā)布器所在線程:http-nio-8080-exec-1
監(jiān)聽器: MyListener
所在線程: http-nio-8080-exec-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
監(jiān)聽器: MyListener2
所在線程: task-1
事件: com.example.event.MyEvent[source=Hello]
事件的數(shù)據(jù):Hello
到此這篇關(guān)于詳解SpringBoot實現(xiàn)同步與異步事件監(jiān)聽的文章就介紹到這了,更多相關(guān)SpringBoot事件監(jiān)聽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項目設(shè)置斷點debug調(diào)試無效忽略web.xml問題的解決
這篇文章主要介紹了SpringBoot項目設(shè)置斷點debug調(diào)試無效忽略web.xml問題的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08SpringCloud微服務(wù)之Hystrix組件實現(xiàn)服務(wù)熔斷的方法
微服務(wù)架構(gòu)特點就是多服務(wù),多數(shù)據(jù)源,支撐系統(tǒng)應(yīng)用。這樣導(dǎo)致微服務(wù)之間存在依賴關(guān)系。這篇文章主要介紹了SpringCloud微服務(wù)之Hystrix組件實現(xiàn)服務(wù)熔斷的方法,需要的朋友可以參考下2019-08-08spring boot基于DRUID實現(xiàn)數(shù)據(jù)源監(jiān)控過程解析
這篇文章主要介紹了spring boot基于DRUID實現(xiàn)數(shù)據(jù)源監(jiān)控過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12mybatis3.3+struts2.3.24+mysql5.1.22開發(fā)環(huán)境搭建圖文教程
這篇文章主要為大家詳細(xì)介紹了mybatis3.3+struts2.3.24+mysql5.1.22開發(fā)環(huán)境搭建圖文教程,感興趣的小伙伴們可以參考一下2016-06-06java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實例詳解
這篇文章主要介紹了java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03SpringBoot+Echarts實現(xiàn)請求后臺數(shù)據(jù)顯示餅狀圖
這篇文章主要介紹了SpringBoot+Echarts實現(xiàn)請求后臺數(shù)據(jù)顯示餅狀圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12