天天看點

JMS定義JMS 規範JMS 消息的可靠性機制消息的持久化存儲消息同步發送和異步發送

定義

Java 消息服務(Java Message Service)是 java 平台中關于面向消息中間件的 API,用于在兩個應用程式之間,或者分布式系統中使用消息進行異步通信。

JMS 是一個與具體平台無關的 API,絕大多數 MOM(面向消息中間件)提供商都對 JMS 提供了支援。

MOM

面向消息的中間件,使用消息傳送提供者來協調消息傳送操作。MOM 需要提供 API 和管理工具。用戶端使用 api 調用,把消息發送到由提供者管理的目的地。接收方收到這個消息确認之前,提供者一直保留該消息。

JMS 規範

規範最初的開發目的是為了使 Java 應用程式能夠通路現有 MOM 系統,并形成一套統一的标準,解決不同消息中間件之間的協作問題。其内容包括:

1. 不同的消息傳送模式或域,例如點對點消息傳送和釋出/訂閱消息傳送

2. 提供于接收同步和異步消息的工具

3. 對可靠消息傳送的支援

4. 常見消息格式,例如流、文本和位元組           

JMS體系結構:

JMS定義JMS 規範JMS 消息的可靠性機制消息的持久化存儲消息同步發送和異步發送

消息傳遞域

JMS 規範中定義了兩種消息傳遞域:點對點(point-to-point )消息傳遞域 和釋出 / 訂閱消息傳遞域

(publish/subscribe)。

點對點消息傳遞域:

1. 每個消息隻能有一個消費者

2. 消息的生産者和消費者之間沒有時間上的相關性。無論消費者在生産者發送消息的時候是否處于運作狀态,都可以提取消息           

釋出訂閱消息傳遞域:

1. 每個消息可以有多個消費者

2. 生産者和消費者之間有時間上的相關性。訂閱一個主題的消費者隻能消費自它訂閱之後釋出的消息。           

JMS 規範允許客戶建立持久訂閱,這在一定程度上降低了時間上的相關性要求。持久訂閱允許消費者消費它在未處于激活狀态時發送的消息。

持久訂閱時,用戶端向 JMS 伺服器注冊一個自己身份的 ID(connection的 ClientID),當這個用戶端處于離線時,JMS Provider 會為這個 ID 儲存所有發送到主題的消息,當客戶再次連接配接到 JMS Provider 時,會根據自己的 ID 得到所有當自己處于離線時發送到主題的消息。

當然這種方式也有一定的影響:當持久訂閱者處于 未激活狀态時,Broker 需要為持久訂閱者儲存消息;如果持久訂閱者訂閱的消息太多則會溢出。

消息結構組成

JMS 消息由及部分組成:消息頭、屬性、消息體:

1. 消息頭(Header) - 消息頭包含消息的識别資訊和路由資訊,消息頭包含一些标準的屬性如:

2. JMSDestination 消息發送的目的地,例如 queue 或者 topic;

3. JMSDeliveryMode 傳送模式,持久模式和非持久模式

4. JMSPriority 消息優先級(優先級分為 10 個級别,從 0(最低)到 9(最高). 如果不設定優先級,預設 4,需要注意的是,JMS provider 并不一定保證按照優先級的順序送出消息)

5. JMSMessageID 唯一識别每個消息的辨別           

屬性

按類型可以分為應用設定的屬性,标準屬性和消息中間件定義的屬性。

1. 應用程式設定和添加的屬性:

Message.setStringProperty(“key”,”value”);           

在發送端,定義消息屬性:

message.setStringProperty("abc","hello");           

在接收端接收資料:

Enumeration enumeration=message.getPropertyNames();
while(enumeration.hasMoreElements()) {
    String key = enumeration.nextElement().toString();
    System.out.println(message.getStringProperty(name));
}           

2. JMS 定義的屬性

傳回所有連接配接支援的 JMSX 屬性的名字:

connection.getMetaData().getJMSXPropertyNames()           

3. JMS provider 屬性

消息體,即實際傳遞的消息内容,JMS API 定義的 5 種消息體格式:

TextMessage java.lang.String 對象

MapMessage key為 String,value 可以是 Java 任何基本類型

BytesMessage 位元組流

StreamMessage Java 中的輸入輸出流

ObjectMessage Java 中的可序列化對象           

一般情況下,隻有JMS provider 屬性會被用到。

JMS 消息的可靠性機制

消息的消費通常包含 3 個階段:客戶接收消息、客戶處理消息、消息被确認。

事務型會話

JMS Session 接口提供了 commit 和 rollback 方法。

在發送端,消息 send 之後且 commit 之前,消息隻會在本地,當 commit 後才會實際發送到broker,當 rollback 後,消息在本地被銷毀;在接收端,消息commit之後意味着目前消息被确認。

commit 或 rollback 方法一旦被調用,一個事務就結束了。

通過在建立 session 的時候使用 true or false 來決定目前的會話是事務性還是非事務性。

connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);           

在事務性會話中,消費端 commit 之後,即

session.commit()           

以後,目前消息會自動被确認掉。

非事務型會話

消息何時被确認取決于建立會話時的應答模式:

acknowledgement mode           

取值如下:

1. Session.AUTO_ACKNOWLEDGE

當客戶成功的從 receive 方法傳回的時候,或者從 MessageListenner.onMessage 方法成功傳回的時候,會話自動确認客戶收到消息。

2. Session.CLIENT_ACKNOWLEDGE

客戶通過調用消息的 acknowledge 方法确認消息。

3. CLIENT_ACKNOWLEDGE 特性

在這種模式中,确認一個被消費的消息将自動确認所有之前已被會話消費的消息。列如,如果目前消費了 10 個消息,确認了第 5 個消息,那麼 0~5 的消息都會被确認。

4. Session.DUPS_ACKNOWLEDGE

消息延遲确認。指定消息提供者在消息接收者沒有确認發送時重新發送消息,這種模式不在乎接受者收到重複的消息。

消息的持久化存儲

消息發送到 Broker 上以後,存儲在 broker 上的消息不應該丢失。可以通過下面的代碼來設定消息發送端的持久化和非持久化特性:

MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);           

對于持久消息,broker 使用存儲-轉發機制,先将消息存儲到穩定媒體中,如果 broker 挂掉了,這些消息不會丢失;broker 恢複正常後,會重新傳送給對應的消費者。

非持久的消息,JMS provider 會将它存到記憶體中,如果 jms provider 當機,那麼記憶體中的非持久消息會丢失。

消息同步發送和異步發送

mq消息發送一般支援同步、異步兩種模式将消息發送到 broker 上。

同步發送過程中,發送者發送一條消息會阻塞直到broker回報一個确認消息,表示消息已經被broker處理。這個機制提供了消息發送的安全性保障,但是會影響用戶端消息發送性能。

異步發送的過程中,發送者不需要等待broker提供回報,性能相對較高。但可能出現消息丢失的情況。是以使用異步發送的前提是在某些情況下允許出現資料丢失的情況。