Spring AMQP雜記之Spring實現簡述

weixin_34019929發表於2018-07-19
7416970-0d7555418baa807e.jpg

上一篇主要介紹了AMQP的一些知識,接下來開始正式步入Spring AMQP。

首先介紹下Spring對於AMQP的抽象

Message:在AMQP中並沒有定義訊息的模型,Spring為了方便我們理解與使用,新增了Message介面,在構建訊息的時候Spring提供了builde API,MessageBuilder.xx.xx的形式使用起來很方便。

Exchange:這個介面和AMQP中定義的exchange基本相同,就不說了

Queue:同上。

Binding:一般叫他繫結關係,AMQP也有對其的抽象模型,只不過我認為他只不過相當於是附加在佇列與交換機上的屬性,所以在上篇關於AMQP的介紹中並沒有詳細說明。呃,其實spring對其的定義就是代表了佇列與交換機的繫結關係。。。

如何連線RabbitMQ

spring提供了ConnectionFactory介面,當我們使用的時候會使用它的實現類CachingConnectionFactory,看名字也知道就是基於快取的連線池,預設的池大小為25。Spring也提供了對於多個connectionFactory的支援介面例如SimpleRoutingConnectionFactory等。

我們使用SpringBoot進行測試,最小化的配置如下

7416970-896042a847dd03ba.png

如何向RabbitMQ傳送與接收訊息?

這裡先給出一個簡單的例子然後再具體講解。

7416970-25ad49aa297a77f0.png


7416970-dc94cd9043f1914c.png

如圖,我們提前宣告瞭一個名為hello的佇列,瀏覽器訪問/send時,可以看到控制檯列印了相應的時間資訊,即被@RabbitListener註解的方法被呼叫了。如果我們開啟RabbitMq的webUI,會發現名為hello的佇列中訊息數量由0變為1再變為0。注意,這裡我們並沒有宣告Exchange,MQ會為我們將佇列繫結到預設的Exchange。


接下來就詳細的說一下這個例子。對於操作RabbitMQ,Spring提供了 RabbitTemplate(對於batch操作,相應的是BatchingRabbitTemplate,在1.6版本以後,spring提供了非同步的Template--AsyncRabbitTemplate)。我們使用它來傳送與接收訊息。當傳送完訊息的時候如何知道本次操作的成功或者失敗呢?預設情況下不能被路由的訊息將會被丟棄,這會導致訊息丟失,不能保證訊息可靠性(訊息可靠性請參照上一篇AMQP介紹中的推薦)。釋出確認機制是保證訊息可靠性的第一步,釋出確認保證我們知道訊息是否成功到達佇列中,返回ack則代表成功,nack則代表失敗。要使用這個特性,我們需要將RabbitTemplate的mandatory屬性和ConnectionFactory的publisherConfirms屬性都設為true。這時我們可以在RabbitTemplate上設定setReturnCallback監聽來接收MQ伺服器返回的狀態資訊了。對於訊息的確認,我們只需要設定RabbitTemplate.ConfirmCallback的回撥方法即可。

7416970-d37dd0d4ac5e2a44.png

當我們每次傳送請求時,都會列印相應的ack,其中correlationData是生產者在傳送資料時可以攜帶的相關資訊。這裡有個問題需要注意一下,RabbitTemplate只允許設定一個callback方法,這時你可以將RabbitTemplate的bean設為單例然後設定回撥。

7416970-0a6de1d45e41acc9.png

這樣的缺點是所有使用這個template的地方都會使用這個回撥,那麼當我們想要為不同的操作定製callBack該怎麼做?如果直接在別的地方繼續設定會報"Only one ConfirmCallback is supported by each RabbitTemplate"異常,這時候我們就需要將RabbitTemplate的作用域設為@Scope,這樣每個bean都是一個新的。難道這樣就可以了麼?我們的service類一般都是單例的,這意味著當service類生成後,注入的RabbitTemplate就已經不變了,這個就是Single域的bean中注入Scope域bean的問題。一種解決方法是實現ApplicationAware介面注入ApplicationContext,每次使用RabbitTemplate時呼叫其getBean方法。一個更好的解決方案是使用spring提供的lookup方法。

7416970-aa2437051db8d6c4.png

spring會幫我們代理lookup註解的方法,每次呼叫都會返回一個全新的bean。但其實平常使用一般都會將傳送方單獨抽取出來實現回撥介面,不會涉及上面的問題,一般都如下配置,注意將template配置成scope即可。

7416970-a145c284e2632fc9.png

RabbitTemplate可以新增訊息轉換器,作用就類似於mvc中配置的@ResponseBody訊息轉換器。

具體如何傳送與接收訊息感覺不用咋說了。。。就send,receive(x,x,x)這個用IDE看一下方法doc就知道咋用了。receive為拉模式,很少使用,關於接收方法我們更常使用的是非同步接收,即推模式,一般使用@RabbitListener 實現

7416970-99cac45de2922a0a.png

當hello佇列中有訊息時,方法會自動呼叫。

像我們平常做web開發,前端想要接受來自後臺的訊息無非倆個方法,前臺請求和後臺推送,前臺輪詢一般就是ajax定時器,推送一般使用WebSocket實現,MQ同樣有兩種模式:輪詢請求佇列看是否有訊息即拉模式,佇列中有訊息即對消費者進行通知即推模式。

對於拉模式,Spring提供了receive,receiveAndConvert,和receiveAndReply方法。接收並回復的方法很有用,比如訂單系統,下單訊息被MQ處理完後再返回訊息給其他佇列,告訴她這個訂單已經完成,可以進行付費操作了。接收並回復呼叫template.receiveAndReply實現自己的接收回撥。對於推模式,專案中基本上使用@RabbitListener註解完成,該註解結合@SendTo註解完成receiveAndReply功能,若沒有sendto,這個方法是不允許有返回值的。對於異常情況,配置@RabbitListener的errorHandler和returnExceptions即可。關於@RabbitListener註解的具體使用其實也挺複雜的,推薦直接看文件。使用監聽器的過程中訊息是預設經過訊息轉換器的,可以手動為其設定訊息轉換器。關於RabbitMQ LIstener的配置可以使用Config方式或者SpringBoot的配置檔案方式。

7416970-bc8219f1f1ddc954.png

上面只是官方文件的一部分,其實除了Listener大部分Config方式的配置都可以用配置檔案方式替代。

宣告佇列與交換機:分為xml方式和Java Config方式(懶得寫了,這個基本官網就是複製貼上)

配置Broker:Spring對其的抽象為RabbitAdmin,也是官網。。

延時佇列實現:設定交換機延時屬性為true,通過convertAndSend中的MessagePostProcessor實現傳送延時訊息,這個方法需要安裝延時交換機這樣的一個外掛(也可以通過死信佇列實現)

7416970-60b2ceca0c959878.png

好了。今天就先寫這麼多,因為實在是寫的太亂了,以後有時間整理一下。。。

相關文章