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