Spring中@RabbitHandler和@RabbitListener的區(qū)別詳析
@RabbitHandler
和 @RabbitListener
是Spring AMQP(特別是針對(duì)RabbitMQ)中常用的兩個(gè)注解,它們?cè)谙⑻幚碇邪缪葜煌慕巧?/p>
@RabbitListener
定義:
@RabbitListener
注解用于標(biāo)記一個(gè)方法,使其成為消息隊(duì)列的監(jiān)聽(tīng)器,即這個(gè)方法負(fù)責(zé)接收來(lái)自RabbitMQ的消息。使用場(chǎng)景:當(dāng)你想讓某個(gè)服務(wù)類(lèi)中的方法直接監(jiān)聽(tīng)某個(gè)RabbitMQ隊(duì)列時(shí),你會(huì)在該方法上使用
@RabbitListener
。功能:
- 它可以指定監(jiān)聽(tīng)的隊(duì)列、交換機(jī)和路由鍵。
- 支持異步處理,可以處理發(fā)送到指定隊(duì)列的消息。
- 可以與Spring的
@Transactional
注解結(jié)合使用,以確保消息處理的事務(wù)性。
@RabbitHandler
定義:
@RabbitHandler
注解用于標(biāo)記一個(gè)方法,作為特定類(lèi)型的消息的處理器。使用場(chǎng)景:在一個(gè)類(lèi)中可能有多個(gè)不同的方法處理不同類(lèi)型的消息。這時(shí),你可以在這個(gè)類(lèi)上使用
@RabbitListener
,然后在每個(gè)處理方法上使用@RabbitHandler
,以便根據(jù)消息類(lèi)型調(diào)用適當(dāng)?shù)姆椒ā?/p>功能:
- 主要用于方法級(jí)別的多態(tài),即在同一個(gè)類(lèi)中根據(jù)消息的不同類(lèi)型來(lái)調(diào)用不同的處理方法。
- 允許你在同一個(gè)監(jiān)聽(tīng)器類(lèi)中定義多個(gè)處理不同類(lèi)型消息的方法。
結(jié)合使用
- 通常,
@RabbitListener
用于類(lèi)級(jí)別或方法級(jí)別,定義消息的入口點(diǎn),即指定哪個(gè)隊(duì)列的消息會(huì)被監(jiān)聽(tīng)。 @RabbitHandler
則用于在同一類(lèi)中的不同方法上,根據(jù)接收到的消息類(lèi)型調(diào)用相應(yīng)的方法。
示例
@Component public class MyMessageListener { @RabbitListener(queues = "myQueue") public void process(String data) { // 處理字符串類(lèi)型的消息 } @RabbitListener(queues = "myQueue") @RabbitHandler public void process(MyCustomObject object) { // 處理 MyCustomObject 類(lèi)型的消息 } }
在這個(gè)示例中,@RabbitListener
用于指定監(jiān)聽(tīng)的隊(duì)列,而 @RabbitHandler
用于區(qū)分不同類(lèi)型的消息應(yīng)由哪個(gè)方法處理。這種結(jié)構(gòu)使得在同一個(gè)監(jiān)聽(tīng)器類(lèi)中可以方便地處理多種類(lèi)型的消息。
更詳細(xì)的例子來(lái)闡明 @RabbitListener
和 @RabbitHandler
在實(shí)際使用中的差異和結(jié)合方式。
示例 1:基本的 @RabbitListener 使用
假設(shè)有一個(gè)場(chǎng)景,你需要監(jiān)聽(tīng)一個(gè)名為 ordersQueue
的RabbitMQ隊(duì)列,并對(duì)收到的訂單消息進(jìn)行處理。
@Component public class OrderService { @RabbitListener(queues = "ordersQueue") public void receiveOrder(String orderJson) { // 解析訂單JSON數(shù)據(jù) Order order = parseOrder(orderJson); // 處理訂單 processOrder(order); } // ...其他方法,如parseOrder和processOrder }
在這個(gè)例子中,@RabbitListener
直接應(yīng)用于方法 receiveOrder
,這意味著這個(gè)方法將監(jiān)聽(tīng) ordersQueue
隊(duì)列,并處理所有接收到的消息。
示例 2:結(jié)合使用 @RabbitListener 和 @RabbitHandler
考慮一個(gè)稍微復(fù)雜的場(chǎng)景,其中一個(gè)服務(wù)需要處理兩種類(lèi)型的消息:文本消息和JSON格式的訂單消息。
@Component @RabbitListener(queues = "mixedMessagesQueue") public class MixedMessageService { @RabbitHandler public void processTextMessage(String text) { // 處理文本消息 System.out.println("Received text message: " + text); } @RabbitHandler public void processOrderMessage(Order order) { // 處理訂單對(duì)象 System.out.println("Received order: " + order); } // ...其他可能的方法 }
在這個(gè)例子中,@RabbitListener
注解應(yīng)用于類(lèi)級(jí)別,意味著這個(gè)類(lèi)中的所有方法都會(huì)監(jiān)聽(tīng) mixedMessagesQueue
隊(duì)列。@RabbitHandler
則用于區(qū)分不同的處理方法:processTextMessage
用于處理文本消息,而 processOrderMessage
用于處理訂單對(duì)象。Spring會(huì)根據(jù)消息的類(lèi)型自動(dòng)選擇合適的方法。
示例 3:使用 @RabbitListener 的多方法監(jiān)聽(tīng)
在某些情況下,你可能希望在同一個(gè)類(lèi)中,不同的方法監(jiān)聽(tīng)不同的隊(duì)列。
@Component public class MultiQueueListener { @RabbitListener(queues = "textQueue") public void processTextMessage(String text) { // 處理來(lái)自textQueue的文本消息 } @RabbitListener(queues = "ordersQueue") public void processOrder(Order order) { // 處理來(lái)自ordersQueue的訂單消息 } }
這個(gè)例子展示了在同一個(gè)類(lèi)中,不同的方法可以監(jiān)聽(tīng)不同的隊(duì)列。processTextMessage
監(jiān)聽(tīng) textQueue
隊(duì)列,而 processOrder
監(jiān)聽(tīng) ordersQueue
隊(duì)列。
這些例子展示了 @RabbitListener
和 @RabbitHandler
在不同場(chǎng)景下的應(yīng)用方式,包括單獨(dú)使用 @RabbitListener
、將 @RabbitListener
與 @RabbitHandler
結(jié)合使用以及在同一個(gè)類(lèi)中使用多個(gè) @RabbitListener
注解來(lái)監(jiān)聽(tīng)不同的隊(duì)列。
附:@RabbitListener或@RabbitHandler使用出現(xiàn)死循環(huán)
異常1問(wèn)題:為什么會(huì)找不到消費(fèi)實(shí)現(xiàn)?
@RabbitListener 或 @RabbitHandler 配置出錯(cuò)
很大原因是取決于content_type 的配置和 方法的形參。
如果通過(guò)客戶端放入隊(duì)列中有個(gè)content_type為空的的消息,@RabbitListener只有形參為String 的Handler,是無(wú)法對(duì)應(yīng)上消費(fèi)實(shí)現(xiàn)的。
@RabbitHandler 沒(méi)有使用可選參數(shù)isDefault
消費(fèi)者找不到任何一個(gè)消費(fèi)實(shí)現(xiàn),就回去找isDefault = true 的 handler,類(lèi)似一個(gè)兜底策略。
異常1問(wèn)題:處理思路
使用Message 作為方法形參
盡量將@RabbitListener 放在類(lèi)上, 使用@RabbitHandler(isDefault = true) 做兜底策略
異常1分析 :死循環(huán)分析
這是一種應(yīng)用級(jí)別的死循環(huán),消息找不到消費(fèi)實(shí)現(xiàn),一直重試直到找到消費(fèi)實(shí)現(xiàn)。這種死循環(huán)原因是配置失誤,要在源頭避免,測(cè)試階段就要消滅?!菊业较@種死循環(huán)的方法再來(lái)填坑】。另外一種必須處理的死循環(huán)是已經(jīng)找到消費(fèi)實(shí)現(xiàn),但是在消費(fèi)的過(guò)程中造成死循環(huán),見(jiàn)異常2:
【異常2】:消費(fèi)過(guò)程中拋出未捕獲Exception
通常是業(yè)務(wù)邏輯導(dǎo)致的異常如NullPointerException,無(wú)腦的做法是try-catch,處理不當(dāng)依舊會(huì)造成死循環(huán)。
異常2問(wèn)題:try-catch后仍然會(huì)死循環(huán)
總結(jié)
到此這篇關(guān)于Spring中@RabbitHandler和@RabbitListener區(qū)別的文章就介紹到這了,更多相關(guān)@RabbitHandler和@RabbitListener區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring實(shí)現(xiàn)HikariCP連接池的示例代碼
在SpringBoot 2.0中,我們使用默認(rèn)連接池是HikariCP,本文講一下HikariCP的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下2021-08-08Java處理InterruptedException異常的理論與實(shí)踐
在使用Java的過(guò)程中,有個(gè)情景或許很多人見(jiàn)過(guò),您在編寫(xiě)一個(gè)測(cè)試程序,程序需要暫停一段時(shí)間,于是調(diào)用 Thread.sleep()。但是編譯器或 IDE 報(bào)錯(cuò)說(shuō)沒(méi)有處理檢查到的 InterruptedException。InterruptedException 是什么呢,為什么必須處理它?下面跟著小編一起來(lái)看看。2016-08-08SpringBoot整合WebSocket實(shí)現(xiàn)聊天室流程全解
WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。本文將通過(guò)SpringBoot集成WebSocket實(shí)現(xiàn)簡(jiǎn)易聊天室,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,感興趣的可以了解一下2023-01-01java 開(kāi)發(fā)使用字符串和數(shù)字的性能分析
這篇文章主要介紹了java 開(kāi)發(fā)使用字符串和數(shù)字的性能分析的相關(guān)資料,需要的朋友可以參考下2017-07-07SpringCloud Feign遠(yuǎn)程調(diào)用與自定義配置詳解
Feign是Netflix公司開(kāi)發(fā)的一個(gè)聲明式的REST調(diào)用客戶端; Ribbon負(fù)載均衡、 Hystrⅸ服務(wù)熔斷是我們Spring Cloud中進(jìn)行微服務(wù)開(kāi)發(fā)非?;A(chǔ)的組件,在使用的過(guò)程中我們也發(fā)現(xiàn)它們一般都是同時(shí)出現(xiàn)的,而且配置也都非常相似2022-11-11