註:文內內容為依據本人理解創作,如果錯誤,請留言告知。
先說需求
如果現有A、B兩個應用程式,B應用希望從A應用獲取到自己感興趣的信息,A和B部署在不同的機房,可能還有C、D、E等更多的這樣的應用程式需要A的這些消息,這就是我們常說的消息中間件的點對點、發布訂閱模式。
說到消息中間件,工作中經常會用到MQ消息中間件,常見的消息中間件有Apache的ActiveMQ以及RabbitMQ。
不管是ActiveMQ還是RabbitMQ都是基於JMS規範的消息中間件,它們都是消息服務的「提供者」。
那麼什麼是 JMS?Java Message Service (JMS)是Java中面向消息中間件為兩個或者多個組件之間發送消息的客戶端,它是生產者和消費者問題的一種實現。JMS是Java平臺企業版的一部分,目的是為了允許組件之間的通訊被鬆耦合、可靠、並且異步。
JMS 的 API 編程模型
1.弄清楚基本元素
首先要搞清楚消息服務中的幾個元素,即 提供者,客戶端、生產者/發布者,使用者/訂閱者,JMS消息,JMS隊列、JMS主題。
JMS 提供者(provider),這個很好理解,可以理解為消息的容器、消息的載體、消息的家,比如ActiveMQ就是一個 JMS 提供者,它為JMS提供了中間的服務。
JMS 客戶端(Client),指的是一個產生或者消費消息的一個進程或者應用。
JMS 生產者/發布者(producer/publisher)、使用者/訂閱者(consumer/subscriber)是對應的關係表示的是創建發送和接收消息的客戶端。
JMS 消息(Message),即一個對象,表示 JMS 傳輸的數據,可以是一段文字,一個序列化的Java對象等等。
JMS 隊列(Queue),這個概念比較重要,JMS中的隊列是一個暫存區域,存儲的是 JMS 中已經發送成功但是等待讀取的消息(點對點模式下)。顧名思義,消息按照發送順序傳遞,JMS隊列保證每條消息都僅被處理一次。
JMS 主題(Topic),指的是一個發布機制,也就是我們常說的發布訂閱模式。
為了方便理解,我找到了這兩張圖片
點對點JMS消息傳遞
發布訂閱JMS消息傳遞
2.想明白兩種發布模式
JMS支持兩種不同的消息發布模式,通過下面的解釋,應該很容易明白。
No.1 點對點
在點對點消息傳遞模式下,消息被生產者傳遞到消息隊列中。這種消息類型基於消息隊列的發送方和接收方,每條消息都被發送到一個特定的隊列中,消費者也就是接收客戶端從保存了消息的隊列中提取消息,隊列的好處就是保證每條消息都會被消費,並且只會被一個消費者消費一次。消息隊列會保留髮送者也就是消息製造者的所有消息,直到消息被消費或者過期。
No.2 發布訂閱
說完了點對點,接下來就是發布訂閱,通過上面的圖片能清晰的看到,發布訂閱和隊列就沒什麼關係了,引入了一個新的概念那就是主題。比如我的微信公眾號「代碼宇宙」就是一個Topic,你關注我,小明也關注了我,小紅也關注了我,那麼我們就是一個發布訂閱的關係, 我發布文章就會推送給你們三個人,你如果取關了.....那麼我發布文章就不會再推送給你,即使你重新關注,你也收不到我之前的推送了。
3.搞懂誰是提供者
要使用JMS就必須有一個人站出來,管理會話、隊列、主題等繁雜工作。從 JavaEE 1.4開始,必須在所有 JavaEE 應用程式伺服器中包含 JMS 提供程序。
以下是常見的JMS提供者程序列表
Amazon SQS's Java Messaging LibraryApache ActiveMQApache Qpid, using AMQPIBM MQJBoss Messaging等等等等
4.什麼是同步消費和異步消費
在JMS中,消息消費可以通過兩個方式來實現。
No.1同步消費
在同步消息消費中,訂閱者/接收者通過調用receive()方法從目的地請求消息。在receive()中,如果消息在給定時間內沒有到達,方法將阻塞直到消息到達或超時。就像普通的帶有返回值的java方法調用一樣。
No.2異步消費
在異步消息消費中,訂閱者可以向消費者註冊(或訂閱)為消息監聽器。消息偵聽器與事件偵聽器相同,每當消息到達目的地時,JMS提供者將通過調用偵聽器的onMessage()方法來傳遞消息,該方法將對消息的內容起作用。
5.JMS 消息組件
JMS Message 即JMS 消息被用來在系統間進行通信。JMS消息具有簡單的格式,但是非常靈活,通常包含以下三個部分。
No.1 消息頭部(Message Header)
JMS 消息提供很多預定義欄位,這些欄位包含客戶機和提供者用來識別這些消息的關鍵信息。
– JMSDestination– JMSDeliveryMode– JMSMessageID– JMSTimestamp– JMSCorrelationID– JMSReplyTo– JMSRedelivered– JMSType– JMSExpiration– JMSPriority
No.2 消息屬性(Message Properties)
在消息屬性中,可以創建和設置消息的屬性。
消息屬性是由應用程式設置或讀取的自定義名稱值對。
消息屬性對於支持過濾消息很有用。
JMS API提供了一些提供者可以支持的預定義屬性,需要注意的是消息屬性是可選的。
No.3 消息體(Message Body)
在消息體中,JMS API定義了五種消息體格式,它們也被稱為消息類型,允許以多種不同的形式發送和接收數據,並提供與現有消息格式的兼容性。它基本上由從JMS發送者發送到接收者的實際消息組成。不同的消息類型有:
文本消息:由javax.jms.TextMessage表示。它用於表示一個文本塊。
對象消息:由javax.jms.ObjectMessage表示。它用於表示一個java對象。
字節消息:由javax . JMS . Bytes消息表示。它用於表示二進位數據。
流消息:由javax.jms.StreamMessage表示。它用於表示java 基元值的列表。
映射消息:用一組關鍵字或值對來表示。
5.必須清楚在哪用
說了這麼多,到底在哪用得到呢?應用場景才是技術的靈魂,JMS的應用場景其實隨處可見,舉幾個例子。
No.1 異步處理
用戶註冊成功後需要發送郵件或者是簡訊,這個時候就可以使用消息中間件的點對點模式來實現,用戶系統無需關心郵件或者簡訊發送結果,僅僅需要將需要發送的郵箱或者手機號通過消息傳遞給專門處理消息發送的系統即可。
No2.應用解耦
訂單和庫存系統是兩個相愛相殺的系統,訂單創建離不開庫存操作,如果訂單系統直接調用庫存系統那麼勢必造成模塊間的強耦合,導致系統復用性、健壯性變低,使用了消息中間件後關係發生了如下變化。
訂單系統->庫存系統(強耦合)
訂單系統->消息中間件->庫存系統(解耦成功)
No3.流量削峰
比如,系統舉行秒殺活動,熱門商品。流量蜂擁而至 100件商品,10萬人擠進來怎麼辦,10萬秒殺的操作,放入消息隊列。秒殺應用處理消息隊列中的10萬個請求中的100個,其他的打回,通知失敗。流量峰值控制在消息隊列處,秒殺應用不會瞬間被懟死,變化如下。
用戶請求->秒殺應用
用戶請求->消息隊列->秒殺應用
No.4 日誌處理
錯誤日誌->消息隊列->日誌處理
用戶行為日誌->消息隊列(kafka)->日誌的存儲或流式處理
說明:日誌處理 可是 kafka的強項,大數據的日誌處理非它莫屬,我沒用過,只知道它很強大。非常強大。
No.5 純粹的消息通訊
本文不以任何MQ講解的原因是,MQ 僅僅是 JMS 中的一部分,理解 JMS 規範後,消息中間件還不是手到擒來?
2020.04.16 晚
保持好奇的心,也許明天再見,晚安。