深刻淺出 JMS(一) - JMS 基本概念

深刻淺出 JMS(一) - JMS 基本概念

1、JMS 是個什麼鬼

JMS 是 Java Message Service 的簡稱,即 Java 消息服務。什麼是消息服務呢,咱們來看一下 Oracle 官方的定義:java

The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java Platform Enterprise Edition (Java EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.

翻譯過來就是說,JMS 是一個消息標準,這種標準容許基於 JavaEE 的應用組件能夠建立,發送,接受及讀取消息。經過 JMS 能夠實現鬆耦合,可依賴及異步的分佈式通訊。那麼在這一段話中咱們應該注意兩點,即首先這是一個標準,相似於 Servlet 標準,並非一個具體的實現。其次,這是一種分佈式的通訊機制,而且是異步的。

JMS 只定義了 Java 中訪問消息中間件的接口,並無給予實現,實現 JMS 接口的消息中間件稱爲 JMS Provider。如 Apache 的 ActiveMQ、以及阿里巴巴的 RocketMQ。編程

2、爲何要學習,使用 JMS

在 Jave 中,若是兩個應用程序之間對各自都不瞭解,甚至這兩個程序可能部署在不一樣的大洲上,那麼它們之間如何發送消息呢?服務器

當前,CORBA、DCOM、RMI 等 RPC 中間件技術已普遍應用於各個領域。可是面對規模和複雜度都愈來愈高的分佈式系統,這些技術也顯示出其 侷限性:網絡

  1. 同步通訊:客戶發出調用後,必須等待服務對象完成處理並返回結果後才能繼續執行;
  2. 客戶和服務對象的生命週期緊密耦合:客戶進程和服務對象進程都必須正常運行,若是因爲服務對象崩潰或者網絡故障致使客戶的請求不可達,客戶會接收到異常;
  3. 點對點通訊:客戶的一次調用只發送給某個單獨的目標對象。

面向消息的中間件(Message Oriented Middleware,MoM)較好的解決了以上問題。發送者將消息發送給消息服務器,消息服務器將消息存放在若干隊列中,在合適的時候再將消息轉發給接收者。session

面向消息的中間件的優勢:數據結構

  1. 發送和接收是異步的,發送者無需等待;
  2. 兩者的生命週期未必相同;
  3. 發送消息的時候接收者不必定運行,接收消息的時候發送者也不必定運行;
  4. 一對多通訊,對於一個消息能夠有多個接收者。

舉個例子,一個應用程序 A 部署在印度,另外一個應用程序部署在美國,而後每當 A 觸發某件過後,B 想從 A 獲取一些更新信息。固然,也有可能不止一個 B 對 A 的更新信息感興趣,可能會有 N 個相似 B 的應用程序想從 A 中獲取更新的信息。在這種狀況下,Jave 提供了最佳的解決方案 JMS,完美解決了上面討論的問題。app

JMS 一樣適用於基於事件的應用程序,如聊天服務,它須要一種發佈事件機制向全部與服務器鏈接的客戶端發送消息。JMS 與 RMI 不一樣,發送消息的時候,接收者不須要在線。服務器發送了消息,而後就無論了;等到客戶端上線的時候,能保證接收到服務器發送的消息。這是一個很強大的解決方案,能處理當今世界不少廣泛問題。異步

3、JMS有什麼優點

  1. 異步:JMS 天生就是異步的,客戶端獲取消息的時候,不須要主動發送請求,消息會自動發送給可用的客戶端。async

  2. 可靠:JMS 保證消息只會遞送一次。你們都遇到太重複建立消息問題,而 JMS 能幫你避免該問題,只是避免而不是杜絕,因此在一些糟糕的環境下仍是有可能會出現重複。分佈式

4、JMS 術語

  • 消息中間件(JMS Provider):指提供了對 JMS 協議的第三方組件,好比 ActiveMQ 就是一個消息中間件,另外比較知名的還有 KFA, Rabbit MQ 等;

  • 消息模式:分爲點對點(Point-to-Point,即P2P)和發佈/訂閱(Pub/Sub),對應的數據結構分別是隊列(Queue)和主題(Topic);

  • 消息(Message): 通訊內容的載體,其結構主要分爲消息頭,屬性和消息體,而且根據存儲結構的不一樣分爲好幾種,後面會詳細提到;

  • 消息生產者(Provider):產生消息的一方,在 P2P 模式下,指消息發送者(Sender),在 P/S 模式下指消息發佈者(Publisher);

  • 消息消費者(Consumer):接收消息的一方,對應於兩種模式分別是消息接收者(Receiver)和消息訂閱者(Subscriber);

5、JMS 消息傳送模型

P2P 模式(點對點消息模型)

圖1.1 P2P模式圖

涉及到的概念:

  1. 消息隊列(Queue)
  2. 發送者(Sender)
  3. 接收者(Receiver)

每一個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到他們被消費或超時。

P2P 的特色:

  1. 每一個消息只有一個消費者(Consumer),即一旦被消費,消息就再也不在消息隊列中。
  2. 發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送了消息以後,無論接收者有沒有正在運行,它不會影響到消息被髮送到隊列。
  3. 接收者在成功接收消息以後需向隊列應答成功。

總結:若是你但願發送的每一個消息都應該被成功處理的話,那麼你須要 P2P 模式。

Pub/Sub 模式(發佈/訂閱消息傳送模型)

圖1.2 Pub/Sub模式圖

涉及到的概念:

  1. 主題(Topic)
  2. 發佈者(Publisher)
  3. 訂閱者(Subscriber)

客戶端將消息發送到主題。多個發佈者將消息發送到 Topic,系統將這些消息傳遞給多個訂閱者。

Pub/Sub 的特色:

  1. 每一個消息能夠有多個消費者。
  2. 發佈者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須建立一個訂閱者以後,才能消費發佈者的消息,並且爲了消費消息,訂閱者必須保持運行的狀態。
  3. 爲了緩和這樣嚴格的時間相關性,JMS 容許訂閱者建立一個可持久化的訂閱。這樣,即便訂閱者沒有被激活(運行),它也能接收到發佈者的消息。

總結:若是你但願發送的消息能夠不被作任何處理、或者被一個消息者處理、或者能夠被多個消費者處理的話,那麼能夠採用 Pub/Sub 模型

6、消息的消費

在 JMS 中,消息的產生和消費是異步的。對於消費來講,JMS 的消費者能夠經過兩種方式來消費消息。

  • 同步:訂閱者或接收者調用 receive 方法來接收消息,receive 方法在可以接收到消息以前(或超時以前)將一直阻塞。

    consumer = session.createConsumer(destination);  
    Message message = consumer.receive();
  • 異步:訂閱者或接收者能夠註冊爲一個消息監聽器。當消息到達以後,系統自動調用監聽器的 onMessage 方法。

    consumer.setMessageListener(new MessageListener(){  
        @Override  
        public void onMessage(Message message) {  
            TextMessage textMessage = (TextMessage)message;  
            try {  
                String value = textMessage.getText();  
                System.out.println("value: "+value);  
            } catch (JMSException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    });

7、JMS 編程接口

在 JMS 的標準協議裏,有幾個重要的接口,先簡單羅列以下:

  1. ConnectionFactory(鏈接工廠):建立 Connection 的工廠,經過這個對象來建立一個到某個消息服務的鏈接。

    用戶用來建立到JMs提供者的鏈接的被管對象。JMS 客戶經過可移植的接口訪問鏈接,這樣當下層的實現改變時,代碼不須要進行修改。管理員在 JNDI 名字空間中配置鏈接工廠,這樣,JMS 客戶纔可以查找到它們。根據消息類型的不一樣,用戶將使用隊列鏈接工廠,或者主題鏈接工廠。

  2. Connection(鏈接) :一個具體的鏈接,由 ConnectionFactory 建立。

    鏈接表明了應用程序和消息服務器之間的通訊鏈路。在得到了鏈接工廠後,就能夠建立一個與 JMS 提供者的鏈接。根據不一樣的鏈接類型,鏈接容許用戶建立會話,以發送和接收隊列和主題到目標。

  3. Destination(目標) :消息存儲的位置,發送者把消息發送到指定位置,消費者從指定位置取消息,那麼這個指定位置多是一個 topic 也多是一個 queue,由這個來表示。

    目標是一個包裝了消息目標標識符的被管對象,消息目標是指消息發佈和接收的地點,或者是隊列,或者是主題。JMS 管理員建立這些對象,而後用戶經過 JNDI 發現它們。和鏈接工廠同樣,管理員能夠建立兩種類型的目標,點對點模型的隊列,以及發佈者/訂閱者模型的主題。

  4. Session(會話) :一個發送或接收消息的線程,由 Connection 建立的用於操做消息的接口,本接口能夠直接用來建立消息的生產者對象。

    表示一個單線程的上下文,用於發送和接收消息。因爲會話是單線程的,因此消息是連續的,就是說消息是按照發送的順序一個一個接收的。會話的好處是它支持事務。若是用戶選擇了事務支持,會話上下文將保存一組消息,直到事務被提交才發送這些消息。在提交事務以前,用戶可使用回滾操做取消這些消息。一個會話容許用戶建立消息生產者來發送消息,建立消息消費者來接收消息。

  5. MessageProducer(消息生產者) :消息的生產者,包括 QueueSender 和 TopicPublisher

    由會話建立的對象,用於發送消息到目標。用戶能夠建立某個目標的發送者,也能夠建立一個通用的發送者,在發送消息時指定目標。

  6. MessageConsumer(消息消費者) :消息的消費者, 包括 QueueReceiver 和 TopicSubscriber

    會話建立的對象,用於接收發送到目標的消息。消費者能夠同步地(阻模式),或異步(非阻寒)接收隊列和主題類型的消息。

  7. MessageListener(消息監聽器) :提供給消費者監聽消息使用的,在添加了某個監聽器以後,一旦消費到達,則會調用其 onMessage 方法。

  8. Message接口(消息):是在消費者和生產者之間傳送的對象,也就是說從一個應用程序創送到另外一個應用程序。

圖1.3 JMS接口之間的關係

8、JMS 消息結構

JMS 客戶端使用 JMS 消息與系統通信,JMS 消息雖然格式簡單可是很是靈活。一個消息有三個主要部分:

  • 消息頭(必須):包含用於識別和爲消息尋找路由的操做設置;
  • 一組消息屬性(可選):包含額外的屬性,支持其餘提供者和用戶的兼容。能夠建立定製的字段和過濾器(消息選擇器);
  • 一個消息體(可選):容許用戶建立五種類型的消息(文本消息,映射消息,字節消思,流消息和對象消息)。

(1) 消息頭

JMS 消息頭預約義了若干字段用於客戶端與JMS提供者之間識別和發送消息,預編譯頭以下:

  • JMSDestination:消息發送的目的地,主要是指 Queue 和 Topic,由 session 建立而由生產者的 send 方法設置。

  • JMSDeliveryMode:傳送模式,有兩種即久模式和非持久模式。一條持久性的消息應該被傳輸"一次僅僅一次",這就意味着若是 JMS 提供者出現故障,該消息並不會丟失,它會在服務器恢復以後再次傳遞。一條非持久的消息最多會傳遞一次,這意味着服務器出現故障,該消息將永遠丟失。由 session 建立而由消息生產者的 send 方法設置。

  • JMSMessageID:惟一識別每一個消息的標識,由 JMS 消息生產者產生。由 send 方法設置。

  • JMSTimestamp:一個 JMS Provider 在調用 send() 方法時自動設置,它是消息被髮送和消費者實際接收的時間差。由客戶端設置。

  • JMSCorrelationI`:用來鏈接到另一個消息,典型的應用是在回覆消息中鏈接到原消息。在大多數狀況下,JMSCorrelationID 用於將一條消息標記爲對 JMSMessageID 標示的上一條消息的應答,不過,JMSCorrelationID 能夠是任何值,不只僅是 JMSMessageID。由客戶端設置

  • JMSReplyTo:提供本消息回覆消息的目的地址,由客戶端設置。

  • JMSRedelivered:若是一個客戶端收到一個設置了 JMSRedelivered 屬性的消息,則表示可能客戶端曾經在早些時候收到過該消息,但並無簽收(acknowledged)。若是該消息被從新傳送,JMSRedelivered=true 不然 JMSRedelivered=flase 。由 JMS Provider 設置。

  • JMSType:消息類型的標識符,由客戶端設置。

  • JMSExpiration:消息過時時間,等於 Destination 的 send 方法中的 timeToLive值加上發送時刻的GMT的時間值。若是timeToLive 值等於零,則 JMSExpiration 被設置爲零,表示該消息永不過時。若是發送後,在消息過時時間以後消息尚未被髮送到目的地,則該消息被清除。由 send 方法設置。

  • JMSPriority:消息優先級,從 0-9 十個級別,0-4 是普通消息,5-9 是加急消息。JMS 不要求 JMS Provider 嚴格按照這十個優先級發送消息,但必須保證加急消息要先於普通消息到達,默認是 4 級。由 send 方法設置。

一個消息的消息頭有這些屬性,咱們能夠按照須要對這個消息的消息進行設計,在將這個消息使用消息生產者的 send() 方法發送到消息服務上。

(2) 消息屬性

咱們能夠給消息設置自定義屬性,這些屬性主要是提供給應用程序的。對於實現消息過濾功能,消息屬性很是有用,JMS API 定義了一些標準屬性,JMS 服務提供者能夠選擇性的提供部分標準屬性。

(3) 消息體

在消息體中,JMS API 定義了五種類型的消息格式,讓咱們能夠以不一樣的形式發送和接受消息,並提供了對已有消息格式的兼容。不一樣的消息類型以下:

  1. Text message: javax.jms.TextMessage,表示一個文本對象。
  2. Object message: javax.jms.ObjectMessage,表示一個JAVA對象。
  3. Bytes message: javax.jms.BytesMessage,表示字節數據。
  4. Stream message:javax.jms.StreamMessage,表示java原始值數據流。
  5. Map message: javax.jms.MapMessage,表示鍵值對。
相關文章
相關標籤/搜索