從入門到精通ActiveMQ(二)

接上一篇《從入門到精通ActiveMQ(一)》,本篇主要討論的話題是:消息的順序消費、JMS Selectors、消息的同步/異步接受方式、Message、P2P/PubSub、持久化訂閱、持久化消息到MySQL以及與Spring整合等知識。
消息的順序消費
在上一篇文章中,我們已經明確知道了ActiveMQ並不能保證消費的順序性,即便我們使用了消息優先級。而在實際開發中,有些場景又是需要對消息進行順序消費的,比如:用戶從下單、到支付、再到發貨等。如果使用ActiveMQ該如何保證消費的順序性呢?

從入門到精通ActiveMQ(二)
消息消費順序性

首先來說,在實際中,我們並不需要的是對全部消息的全局有序消費,我們僅僅需要的是局部業務有序性消費。比如說,我們僅僅需要的是一個用戶的下訂單、支付、發貨這個過程的3條消息有序消費。

比如,我們可以根據用戶ID簡單做一個HASH,將消息定位到不同的隊列上,也就意味着同一個用戶的消息將發往同一個隊列。這樣做的好處在於,多個隊列之間可以並行處理。

然後,在隊列上可以對一段時間上的消息按照用戶分組進行排序,這只是一個少量消息的局部排序而已,比如Queue-A上有一個用戶的3條消息(訂單消息msg1、支付消息msg2、發貨消息msg3),那麼,msg1將交給訂單業務系統,處理完成後,msg2交給支付系統,處理完成後,msg3交給發貨系統。雖然這個處理過程是同步的(一條消息處理完,在接着處理),但是它的併發性,系統的處理能力並沒有下降!爲什麼這麼說呢?

假設,msg1/msg2/msg3處理各需要0.1S,如果訂單業務系統、支付系統、發貨系統並沒有分開,而是一個“大系統”,那麼顯然訂單業務在0.1S完成後,需要等待後面的支付、發貨邏輯處理完才能繼續工作,意味着訂單業務幹了0.1S的活,等了0.2S,導致在0.3秒內訂單業務只處理了1條消息。而現在這3個系統是分開的,那麼在0.3S內,訂單業務系統可以處理3條消息,而且沒有業務系統閒着!

實際上,RocketMQ在消費順序性這塊要比ActiveMQ要強大些,後期在RocketMQ專題中再爲大家介紹。

JMS Selectors
JMS Selectors,即消息選擇器。在《ActiveMQ從入門到精通(一)》中,介紹過消息的組成部分,其中談到消息對象有消息屬性,用於消息選擇器。我們來看一個代碼片段,你就會明白:從入門到精通ActiveMQ(二)

生產者片段
從入門到精通ActiveMQ(二)

消費者片段

需要注意一下幾點:

第一,生產者端需要設置消息屬性,一定要注意的是setXxxProperty(filed,value)

第二,給出條件,其實本質上就是SQL92語法

第三,創建消費者的時候,指定條件即可

消息的同步 AND 異步 接受
消息的接受,我們已經知道,可以通過消費者的receive()/receive(long time)/receiveNoWait(),這種方式是client端主動接受消息,可以理解爲消息的同步接受。要知道這種同步的消息接受方式,是讓我們很難受的,我們不得不寫一個死循環來不斷接受消息。那麼有沒有一種比較優雅的方式,比如我們設置一個類似消息監聽的機制,一旦隊列上有消息了,那麼回調我們的message handler進行處理呢?從入門到精通ActiveMQ(二)

Message Listener

消息的異步接受是指當消息到達時,ActiveMQ主動通知客戶端。可以通過註冊一個實現了MessageListener接口的對象到MessageConsumer。MessageListener只有一個必須要實現的方法,即onMessage。在發往Destination的消息時,會調用該方法。

這種異步接受“貌似”是ActiveMQ主動的推送消息給消費者,其本質還是消費者輪詢消息服務器導致的,只不過這個過程被封裝了!

Message
JMS程序的核心在於,生產和消費的消息能夠被其他程序所使用到。JMS Message是一個既簡單又不乏靈活的基本格式,由消息頭、屬性、消息體3部分組成。從入門到精通ActiveMQ(二)

Message

注意,在消費者端,我們接受到消息後,一般需要通過instanceof來判斷類型後在進行處理!

在ActiveMQ中,還存在一類臨時消息,就是通過創建臨時隊列/臨時主題,如果Connection一旦關閉,那麼臨時目標就關閉,消息內容也就消失。瞭解下即可,實際中並不適用。

P2P or Pub/Sub
上2張圖,你就會明白這2種模式的區別了。
從入門到精通ActiveMQ(二)

P2P

生產者端發送一條消息,消費者端只會有一個消費者消費這個消息。好像打電話,一對一通信!

從入門到精通ActiveMQ(二)
Pub/Sub

一對多通信,發送一條消息,所有訂閱了該目標的消費者都會收到消息。

P2P、Pub/Sub在代碼上的區別點僅僅在於,目標類型的創建是createQueue or createTopic,其他一切照舊!

對於訂閱模式,對訂閱者提出了特殊的要求,要想收到消息,必須先訂閱,而且訂閱進程必須一直處於運行狀態!實際上,有時候消費者重啓了下,那麼這個消費者將丟失掉一些消息,那麼能否避免這樣的情況呢?ActiveMQ已經替我們想好了,就是持久化訂閱!

持久化訂閱
所謂持久化訂閱,打個比方,就是說跟MQ打聲招呼,即便我不在,那麼給我發送的消息暫存在MQ,等我來了,再給我發過來。說白了,持久化訂閱,需要給MQ備個案(你是誰,想在哪個Topic上搞特殊化)!看一個代碼片段:
從入門到精通ActiveMQ(二)

持久化訂閱機制

每一個持久化訂閱者都應該有一個唯一的ID作爲標示以及要在哪個Topic上進行持久化訂閱,一旦這些信息告知MQ之後,那麼以後不論持久化訂閱者在不在線,那麼他的消息會暫存在MQ,以後都會發給他!

持久化消息到MySQL
在前文中已經提及默認情況下,ActiveMQ是開啓持久化消息機制的,並且是持久化到kahadb的,但是"很可惜"kahadb對我們不是很友好的可視化,其實ActiveMQ提供了配置的方式讓我們來選擇持久化消息到哪裏,這裏我以到MySQL爲例來說明。(實際上ActiveMQ已經在conf配置文件中提供了相應的例子,我這裏就簡單說明下)從入門到精通ActiveMQ(二)

在activemq.xml的<broker>節點中增加MySQL信息

注意到這個bean的id,這個是要被引用的。
從入門到精通ActiveMQ(二)

註釋kahadb,啓用持久化到MySQL配置

實際中,我們會持久化到哪裏呢?一般情況下,比如到kahadb,比如到leveldb,因爲這些數據庫的性能要較MySQL更高些,我們並不關心消息的“可視化”,更加關心的是消息在持久化的同時更加高效!

與Spring整合
這裏我將爲大家演示Spring和ActiveMQ整合的核心要素。採用Spring,不要Web容器,不涉及Spring-MVC,而且在這裏我將採用JUnit + Spring-Test來進行測試!在文章末尾我將提供源碼下載。OK,先來看一眼工程截圖:
從入門到精通ActiveMQ(二)

工程結構

第一步:POM.XML配置
從入門到精通ActiveMQ(二)

maven dependency tree

第二步:MQ信息配置文件、Spring配置文件
從入門到精通ActiveMQ(二)

spring-context.xml從入門到精通ActiveMQ(二)

下面我們重點關注spring-activemq.xml:

從入門到精通ActiveMQ(二)
ConnectionFactory

注意從ActiveMQConectionFactory到PooledConnectionFactory,到Spring提供的SingleConnectionFactory,就是一個適配的過程。

從入門到精通ActiveMQ(二)

生產者、消費者配置

注意Spring的套路經常是這樣的,提供XxxTemplate,比如HibernateTemplate,對於JMS,提供了JmsTemplate。

生產者應該持有JmsTemplate進行發送消息。

消費者,提供監聽器、監聽的目的地、連接工廠即可。

上面的配置,只是一個非常簡單的示例,比如是發送到隊列,還是發送到主題,事務的配置,簽收機制的配置,ttl/priority等配置在後文通過看一下源碼,你就會知道該如何配置了。

第三步:消費者實現監聽器
從入門到精通ActiveMQ(二)

spring提供的接口

第四步:生產者
從入門到精通ActiveMQ(二)
通過注入拿到JmsTemplate

第五步:利用Junit4 + SpringTest方式進行測試

我們以前在測試Spring這一塊,大都是通過手動編碼的方式(加載XML,setter/getter bean)進行,這裏我將爲大家介紹一種全新的方式測試Spring程序!從入門到精通ActiveMQ(二)

測試基類

爲什麼要提供一個測試基類呢?因爲我們可能有很多個測試類,如果有了這個基類,其他測試類繼承它,就可以自動獲得測試基類的屬性了。

@RunWith 指明採用SpringJunit4進行測試

@ContextConfiguration 告訴配置文件在哪裏

從入門到精通ActiveMQ(二)

生產者測試類

發現沒有,這樣寫Junit單元測試,和以前感覺不一樣!

其實,SpringTest + Junit4還提供了很多功能強大的地方,比如可以設置數據庫事務。如果我們在測試的過程結束後,希望回滾數據庫的話,很簡單,只需要在相應方法上打上註解即可。

運行結果
從入門到精通ActiveMQ(二)

Test Result

JmsTemplate
看一下屬性:
從入門到精通ActiveMQ(二)

JmsTemplate

很多屬性,是不是很熟悉呢?

JmsTemplate的父類中有一個重要屬性:

從入門到精通ActiveMQ(二)
pubSubDomain

默認情況下,是P2P模式,如果將這個屬性配置成true,那麼將是主題模式。

OK,到這裏這篇博客的內容就介紹完畢了。

本篇博客工程代碼獲取方式關注 轉發+評論 私信“工程代碼”即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章