消息傳遞和 Java 消息服務(JMS)

消息傳遞系統用於構建高可靠、可伸縮及靈活的分佈式應用程序。本文從大體上討論了消息傳遞系統,簡要敘述了它們的特性及類型,然後描述開發人員如何可以使用 Java 消息服務(Java Message Service ,JMS) 編寫基於消息的應用程序。

正如許多以前在同步、可靠性、可伸縮性和安全性方面的未知問題一樣,分佈式應用程序潛在的問題也是不斷增長的。一種解決方案是建立在鬆散耦合組件基礎上的消息傳遞系統,這些組件之間通過消息進行通信。

Java 消息服務提供了一致的 API 集合,讓開發人員可以訪問許多消息傳遞系統產品的公共特性。

什麼是消息傳遞系統?
從它的本質上講,消息傳遞系統允許不同的非耦合應用程序以異步方式進行可靠通信。消息傳遞系統體系結構一般用各個組件間的點對點關係代替客戶端/服務器模型,其中每個點可以發送消息到其他點,或從其他點接收消息。

相對於更加傳統的分佈式計算模型,消息傳遞系統提供了許多強大的優勢。首先,它們倡議在消息消費者和消息生產者之間進行“鬆散耦合”。在生產者和消費者之間存在着高級匿名:對於消息消費者,它不關心 誰 產生消息,在網絡上生產者在 哪裏,或者消息是 何時 產生的。

這使得可以構建動態、可靠和靈活的系統,由此可以修改子應用程序的整體組合,而不會影響到系統的其餘部分。 消息傳遞系統的其他優勢包括高可伸縮性(商業實現鼓吹可以支持好幾萬個客戶端,以及支持每秒進行好幾萬個操作)、容易集成到異構網絡以及由於減少了單點故障而提高了可靠性。

由於消息傳遞系統固有的可靠性和可伸縮性,所以它們用於解決許多商業和計算科學問題。例如,它們是這樣的一些不同的應用程序的基礎:工作流、網絡管理、通信服務(通過 IP 的語音、有聲郵件、尋呼機和電子郵件)、客戶服務、天氣預報和供應鏈管理等系統。此外,消息傳遞系統是無價的,因爲它作爲“glue”(膠水)把完全不同的系統聯繫在一起,使之能夠合併和獲取消息。

消息系統類型
通常使用兩種消息傳遞系統模型。

發佈/訂閱
發佈/訂閱 (pub/sub) 消息傳遞系統支持事件驅動模型,在這種模型中,信息消費者和生產者參與消息的傳輸。生產者“發佈”事件,而消費者“訂閱”感興趣的事件並消費事件。生產者把消息把與特定主題關聯起來,然後消息傳遞系統根據消費者所註冊的感興趣主題,把消息路由給消費者。

點對點
在點對點消息傳遞系統中,消息是被路由到各個消費者的,該消費者維護“傳入”消息隊列。消息傳遞應用程序發送消息到指定隊列,然後客戶端從隊列中檢索消息。 供應商經常會支持點對點模型或發佈/訂閱消息傳遞模型,或者同時支持這兩種模型。

既然已經從大體上認識了消息系統,現在讓我們來看一下 Java 開發人員是如何可以利用它們的能力的。

Java 消息服務
Java 消息服務是 J2EE (Java 2 Enterprise Edition) 套件的一部分,它提供了標準 API,Java 開發人員可以使用這些 API 來訪問企業消息系統的共同特性。JMS 支持發佈/訂閱和點對點模型,並允許創建由任意 Java 對象組成的消息類型。

設計目標
JMS 的基本設計目標是爲了提供一組一致的接口,消息傳遞系統客戶端可以獨立地使用這些接口,而不必關心基礎消息系統的提供商。 這樣,客戶端應用程序不僅可以跨計算機體系結構和操作系統進行移植,而且也可以跨消息傳遞產品進行移植。寫到 JMS 的客戶端應用程序將正常工作,而不用在所有符合 JMS 的消息傳遞系統上做修改(這可以與組件所運行的基礎中間件上的 Enterprise Java Beans 組件的獨立性進行比較)。

JMS 也設計成:

最小化消息傳遞系統提供商爲其產品實現 JMS API 所需的工作量。
提供了普通消息傳遞系統的大多數功能。
許多消息系統提供商已經爲它們的產品實現了 JMS,允許 Java 訪問它們系統的功能。

JMS 客戶端可以使用 Java 設施
由於 JMS 客戶端是基於 Java 的,因此它們可以利用現有的 Java API,比如:用於數據庫訪問的 JDBC、JavaBeans 組件模型、用於命名服務的 JNDI、用於客戶端事務控制的 JTA 或用於企業應用程序服務的任何 J2SE 和 J2EE API。

JMS 細節
現在,我們從消息開始,來看一下使用 JMS 構建消息傳遞系統客戶端的細節。

什麼是消息?
在消息傳遞系統中,應用程序之間的通信點是消息本身,因此使用 JMS 的開發人員必須理解消息。

儘管消息傳遞系統之間消息定義區別甚大,但 JMS 提供了統一的方式用於描述和訪問消息。JMS 消息由三部分組成:

消息標題
用於消息標識。例如,標題用於確定指定的消息是否適合於“訂閱者”。
屬性
用於特定於應用程序、特定於提供商及可選的標題字段。
消息體
保存消息的內容。支持幾種格式,其中包括:TextMessages——用於包裝簡單的 String; 和 ObjectMessages——用於包裝任意的 Java 對象(它們必須是可序列化的)。也支持其他的格式。
TextMessages
TextMessage 用於包裝簡單的 String 對象。在只傳遞字符串的情形下,這是有用的。期望許多消息傳遞系統將以 XML 爲基礎,TextMessages 是它們的自然容器。

創建 TextMessage 對象是簡單的,如下面兩行代碼所指出的那樣:

TextMessage message = session.createMessage();
message.setText("hello world");
(在下一節,我們將看到 session 對象)。

以這種方式創建的 TextMessage 準備發佈到消息傳遞系統中。

ObjectMessages
顧名思義,ObjectMessage 是包裝了 Java 對象的消息。任何可序列化的 Java 對象均可用作 ObjectMessage。如果多個對象必須在單個消息中傳輸,那麼可以使用包含幾個可序列化對象的 Collection 對象(比如 List 或 Set)。

下面展示瞭如何創建 Object 消息:

ObjectMessage message = session.createObjectMessage();
message.setObject(myObject);

關於 JNDI
像許多 J2EE API 一樣,JMS 利用了 JNDI(Java 命名和目錄接口)來發現所需資源。詳細討論 JNDI 超出了本文的範圍,但可從如下地址找到更多的進一步信息:Java 命名和目錄接口 (JNDI)。

構建 JMS 客戶端
可以遵循下面的基本步驟來構建典型的 JMS 客戶端:

創建到消息傳遞系統提供商的連接。
創建會話用於發送和接收消息。
創建 MessageProducers 和 MessageConsumers 來創建或接收消息。
一旦這些步驟執行完畢,消息生產的客戶端將創建消息,並把它們發佈到主題,而消息消費的客戶端將偵聽與主題有關的消息,並在它們到達時消費它們。

爲了詳細展示它是如何工作的,我們研究了典型的消息生產者,它用於在 pub/sub 消息傳遞系統中把消息發佈到特定的主題。注意,爲簡潔起見,省略了所有異常處理代碼。

創建連接
連接爲客戶端提供了對基礎消息傳遞系統的訪問,並執行資源分配和管理。連接是使用 ConnectionFactory 創建的,而 ConnectionFactory 通常是使用 JNDI 查找的。

下面這些代碼展示了創建連接過程中涉及的一些步驟:

Context messaging = new InitialContext();
// get JNDI context
TopicConnectionFactory topicConnectionFactory =
(TopicConnectionFactory)
messaging.lookup("TopicConnectionFactory");
TopicConnection topicConnection =
topicConnectionFactory.createTopicConnection();


創建會話
會話是輕量級 JMS 對象,它提供了用於生產和消費消息的上下文。會話用於生成消息生產者和消息消費者,以及用於生成消息本身。

TopicSession session =
topicConnection.createTopicSession(false,Session.CLIENT_ACKNOWLEDGE);

createTopicSession() 的兩個參數控制事務和消息的確認。

查找主題
主題(也稱標題、組或頻道)是通過 JNDI 來查找的。主題標識了發送中或接收中的消息。在發佈/閱系統中,訂閱者訂閱了指定的主題,而發佈者把主題與它們發佈的消息關聯。

這裏我們創建了一個稱爲“WeatherData”的主題。

Topic weatherTopic = messaging.lookup("WeatherData");

啓動連接
在上面的初始化過程中,爲了防止初始化期間出現不可預知的行爲,消息流是被禁止的。一旦初始化完成,必須告訴連接開始消息流。

topicConnection.start();

創建消息生產者
在發佈/訂閱領域中,生產者把消息發佈到指定主題。下面代碼展示了發佈者的創建及後續的簡單文本消息的生成和發佈。

TopicPublisher publisher =
session.createPublisher(weatherData);
TextMessage message = session.createMessage();
message.setText("temperature: 35 degrees");

publisher.publish(message);


創建訂閱者及點對點系統的 JMS 客戶端遵循相似的過程。可以在 [1] 中找到這一過程的完整細節。

結束語
我們已經看到在使用 JMS 來構建基於消息傳遞的應用程序的過程中涉及的基本概念。在編寫 JMS 代碼之前,你將需要訪問符合 JMS 的消息傳遞系統。可從如下地址獲取符合 JMS 的供應商的列表:

JMS 供應商


創建和構建基於 JMS 的應用程序是簡單的,可是它爲構建強大、可伸縮和高可靠的分佈式系統提供了基礎。

注意,JMS 遠遠比本文討論的要複雜,併爲下面的這些提供了支持:管理、安全、錯誤處理和恢復、優化、分佈式事務、消息排序和消息確認等。

有關 Java Message Service 的進一步信息和文檔,請參閱:

Java Message Service 文檔

參考資料
本文中的許多內容是以 Java Message Service 文檔 爲基礎的。

本文的再版須有 SunServer 許可。

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