定義
Java 消息服務(Java Message Service)是 java 平台中關于面向消息中間件的 API,用于在兩個應用程式之間,或者分布式系統中使用消息進行異步通信。
JMS 是一個與具體平台無關的 API,絕大多數 MOM(面向消息中間件)提供商都對 JMS 提供了支援。
MOM
面向消息的中間件,使用消息傳送提供者來協調消息傳送操作。MOM 需要提供 API 和管理工具。用戶端使用 api 調用,把消息發送到由提供者管理的目的地。接收方收到這個消息确認之前,提供者一直保留該消息。
JMS 規範
規範最初的開發目的是為了使 Java 應用程式能夠通路現有 MOM 系統,并形成一套統一的标準,解決不同消息中間件之間的協作問題。其内容包括:
1. 不同的消息傳送模式或域,例如點對點消息傳送和釋出/訂閱消息傳送
2. 提供于接收同步和異步消息的工具
3. 對可靠消息傳送的支援
4. 常見消息格式,例如流、文本和位元組
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提供回報,性能相對較高。但可能出現消息丢失的情況。是以使用異步發送的前提是在某些情況下允許出現資料丢失的情況。