我是否應該學習本教程 | 第 1 頁(共2 頁) |
本教程提供了對 Java Message Service (JMS)的概述,並提供了用它開發程序的一些基礎知識。JMS 是由 Sun Microsystems 開發的,它爲 Java 程序員提供一種訪問企業消息系統的方法,即 面向消息的中間件 (MOM)。MOM 通過中間媒介以間接方式在應用程序之間異步傳送數據,用這種方法提供一種以鬆散耦合的靈活方式集成應用程序的機制。
在開始學習本教程之前,讀者應該熟悉 Java 編程和麪向對象編程的概念。
編寫在本教程中描述的程序需要一個編輯環境,它可以是像操作系統編輯器這樣的基本編譯環境。在進行開發時,許多人使用集成開發環境(IDE),因爲它有專門爲編寫和測試代碼而設計的調試程序和其他特性。
編寫這些程序需要 Java 編譯器(javac.exe),還需要 javax.jms
包中的 JMS 類和 javax.naming
包中的 Java Naming and Directory Interface (JNDI)類。可以從 Sun 下載它們:JMS 和 JNDI。
要執行並測試這些程序,需要訪問 JMS 的供應商實現。大多數 Java 2 Enterprise Edition (J2EE)供應商都會提供 JMS 的一種實現。要想獲得設置 JMS 運行時程序和執行程序的有關信息,請參閱供應商文檔。
有些編程決定將取決於所使用的 JMS 版本(請參閱 JMS 1.1 中的新內容:統一域)。 JMS 版本 1.1 是爲了向後兼容性才而支持 點對點接口 和 Pub/sub 接口,如果使用基於 JMS 版本 1.1 的供應商進行絕對全新的程序開發,則完全可以跳過本教程中有關這些主題的章節。
企業消息系統 | 第 1 頁(共8 頁) |
Java Message Service 是由 Sun Microsystems 開發的,它爲 Java 程序提供一種訪問 企業消息系統 的方法。在討論 JMS 之前,我們分來析一下企業消息系統。
企業消息系統,即 面向消息的中間件(MOM),提供了以鬆散耦合的靈活方式集成應用程序的一種機制。它們提供了基於 存儲和轉發 的應用程序之間的異步數據發送,即應用程序彼此不直接通信,而是與作爲中介的 MOM 通信。
MOM 提供了有保證的消息發送(至少是在儘可能地做到這一點),應用程序開發人員無需瞭解遠程過程調用(PRC)和網絡/通信協議的細節。
消息靈活性 | 第 2 頁(共8 頁) |
如下圖所示,應用程序 A 與應用程序 B 通過使用 MOM 的應用程序編程接口(API)發送消息進行通信。
MOM 將消息路由給應用程序 B,這樣,消息就可以存在於完全不同的計算機上,MOM 負責處理網絡通信。如果網絡連接不可用, MOM 會存儲消息,直到連接變得可用時,再將消息轉發給應用程序 B。
靈活性的另一方面體現在,當應用程序 A 發送其消息時,應用程序 B 甚至可以不處於執行狀態。MOM 將保留這個消息,直到應用程序 B 開始執行並試着檢索消息爲止。這還防止了應用程序 A 因爲等待應用程序 B 檢索消息而出現阻塞。
這種異步通信要求應用程序的設計與現在大多數應用程序不同,不過,對於時間無關或並行處理,它可能是一個極其有用的方法。
鬆散耦合 | 第 3 頁(共8 頁) |
企業消息系統的真正威力在於應用程序的 鬆散耦合。在前一頁的圖表中,由應用程序 A 發送消息指定一個特定目標,如“訂單處理”。而現在,是由應用程序 B 提供訂單處理功能。
但是在將來,我們可以用不同的訂單處理程序替換應用程序 B,應用程序 A 將不再是明智之選。替換應用程序將繼續發送消息完成“訂單處理”,而消息也仍將得到處理。
同樣,我們也可以替換應用程序 A,只要替換應用程序繼續發送消息進行“訂單處理”,訂單處理程序就無需知道是否有一個新的應用程序在發送訂單。
發佈和訂閱 | 第 4 頁(共8 頁) |
最初,開發企業消息系統是爲了實現 點對點模型 (PTP),由一個應用程序生成的每個消息都由另一個應用程序接收。近年來,出現了一種新的模型,叫做 發佈與訂閱 (或者 pub/sub)。
Pub/sub 用稱爲 主題(topic) 的內容分層結構代替了 PTP 模型中的惟一目的地,發送應用程序 發佈 自己的消息,指出消息描述的是有關分層結構中的一個主題的信息。
希望接收這些消息的應用程序 訂閱了 這個主題。訂閱包含子主題的分層結構中的主題的訂閱者可以接收該主題和其子主題發表的所有消息。
下圖展示了發佈和訂閱模型。
多個應用程序可以就一個主題發佈和訂閱消息,而應用程序對其他人仍然是匿名的。MOM 起着 代理(broker) 的作用,將一個主題已發表的消息路由給該主題的所有訂閱者。
JMS 是什麼? | 第 5 頁(共8 頁) |
Java Message Service 規範 1.1 聲稱:
JMS 是一組接口和相關語義,它定義了 JMS 客戶如何訪問企業消息產品的功能。
在 JMS 之前,每一家 MOM 廠商都用專有 API 爲應用程序提供對其產品的訪問,通常可用於許多種語言,其中包括 Java 語言。JMS 通過 MOM 產品爲 Java 程序提供了一個發送和接收消息的標準的、便利的方法。用 JMS 編寫的程序可以在任何實現 JMS 標準的 MOM 上運行。
JMS 可移植性的關鍵在於:JMS API 是由 Sun 作爲一組接口而提供的。提供了 JMS 功能的產品是通過提供一個實現這些接口的提供者來做到這一點的。
開發人員可以通過定義一組消息和一組交換這些消息的客戶機應用程序建立 JMS 應用程序。
JMS 的目標 | 第 6 頁(共8 頁) |
更好地理解 JMS 有助於瞭解 JMS 規範的制定者設置的目標。
現在,市場上有許多企業消息產品,生產這些產品的幾家公司也參與了 JMS 的開發。
現有的這些系統的能力和功能各不相同。這些制定者知道如果 JMS 結合所有現有系統的所有功能,那麼它會變得過於複雜。同樣,他們相信,他們也不能讓 JMS 只侷限於所有系統共有的那些特性。
制定者相信,讓 JMS 包括實現“高級的企業應用程序”所需要的所有功能是很重要的。
JMS 規範中聲明, JMS 的目標是:
- 定義一組消息公用概念和實用工具。
- 最少化程序員使用消息時必須學習的概念。
- 最大化消息應用程序的可移植性。
- 最小化實現一個提供者所需的工作量。
- 爲點對點和 pub/sub 域 提供客戶機接口。“域”是用於在前面討論的消息模型的 JMS 術語。(注意:提供者不需要實現兩個域。)
JMS 1.1 中的新內容:統一域 | 第 7 頁(共8 頁) |
在 JMS 1.1 以前的版本中,每一個域都有自己的特定於該域的一組客戶機接口。JMS 版本 1.1 提供了單一的一組接口,它允許客戶機可以在兩個域中發送和接收消息。這些“域無關的接口”保留了每一個域的語義和行爲,是實現 JMS 客戶機的最好選擇。支持特定於域的接口是爲了向後兼容性,新的開發不該使用它。
統一域的好處是:
- 它展示了用於客戶機編程的更簡單的編程模型。
- 隊列和主題的操作可以是同一事務的一部分。
- 它爲 JMS 提供者提供了優化其實現的機會。
哪些是 JMS 沒有提供的 | 第 8 頁(共8 頁) |
以下特性在MOM 產品中常見,但在 JMS 規範中沒有出現。儘管 JMS 制定者承認它們對於開發功能強大的消息應用程序很重要,但是這些功能是特定於 JMS 提供者的。
JMS 提供者可以以任何他們願意的方式自由實現這些功能:
- 負載平衡和容錯
- 錯誤和諮詢系統消息和通知
- 管理
- 安全性
- Wire 協議
- 消息類型倉庫
JMS概述和體系結構
應用程序 | 第 1 頁(共15 頁) |
JMS 應用程序由以下元素組成:
- JMS 客戶機。 用 JMS API 發送和接收消息的 Java 程序。
- 非 JMS 客戶機。 認識到傳統程序通常整個 JMS 應用程序的一部分是非常重要的,在規劃時必須優先考慮它們的存在。
- 消息。就JMS 應用程序設計而言,通過JMS 和非 JMS 客戶機所交換的消息的格式和內容是完整的。
- JMS 提供者。 如前所述,JMS 定義了一組接口,供應者必須提供特定於其 MOM 產品的具體實現。
- 管理對象。 消息系統提供者的管理員創建的、獨立於提供者的專有技術的對象。
管理對象 | 第 2 頁(共15 頁) |
MOM 產品的提供者在實現消息時使用的機制和技術有很大不同。爲了保持 JMS 客戶機的可移植性,實現了 JMS 接口的對象必須與提供者的專有技術隔離。
完成這項任務的機制是 管理對象。這些實現 JMS 接口的對象由提供者的消息系統的管理員創建,並被放置在 JNDI 名字空間中。
然後由 JMS 程序檢索這些對象,通過它們實現的 JMS 接口訪問這些對象。JMS 提供者必須提供允許創建受管理對象及它們在 JNDI 名字空間中的存放地的工具。
有兩種受管理對象:
ConnectionFactory
:用於創建到提供者的底層消息系統的連接。Destination
:用 JMS 客戶機來指定正發送消息的目的地或正接收消息的來源。
儘管受管理對象本身就是特定於提供者實現的類的例子,但可以使用可移植機制(JNDI)檢索它們,並且可以通過可移植接口(JMS)訪問它們。JMS 程序只需要知道管理對象的 JNDI 名稱和 JMS 接口類型即可,無需瞭解特定於提供者的知識。
接口 | 第 3 頁(共15 頁) |
JMS 定義了一組封裝各種消息概念的高級接口。而這些接口又因爲兩個消息域——PTP 和 pub/sub——進行了進一步地定義和定製。
高級接口包括:
ConnectionFactory
:一個創建Connection
的受管理對象。Connection
:連接到提供者的活動連接。Destination
:一個封裝消息目的地的身份的受管理對象,如消息的來源地和發送地。Session
:發送和接收消息的單線程環境。爲了簡化,並且因爲Session
控制事務的緣故,通過多個線程進行併發訪問受到了限制。可以將多個Session
用於多線程應用程序。MessageProducer
:用於發送消息。MessageConsumer
:用於接收消息。
接口 (續) | 第 4 頁(共15 頁) |
下表列出了從每一個高級接口繼承的特定於域的接口。
高級接口 | PTP 域 | Pub/sub 域 |
---|---|---|
ConnectionFactory |
QueueConnectionFactory |
TopicConnectionFactory |
Connection |
QueueConnection |
TopicConnection |
Destination |
Queue |
Topic |
Session |
QueueSession |
TopicSession |
MessageProducer |
QueueSender |
TopicPublisher |
MessageConsumer |
QueueReceiver ,QueueBrowser |
TopicSubscriber |
接口:JMS 1.1 中的變化 | 第 5 頁(共15 頁) |
在 JMS 以前的版本中,高級接口是特定於域的接口的父接口,並且只包含在兩個域中共有的那些功能。JMS 提供者沒有提供高級接口的實現。在 JMS 1.1 中,一些高級接口現在則被認爲是“公用接口”,並且它們包含兩個域的所有功能; JMS 提供者必須提供這些接口的實現。儘管公用接口仍然是特定於域的接口的父接口,但它們現在是 JMS 客戶機編程的首選方法,並且它們提供特定於域的接口只爲了後向兼容。
下面重新列出了前一小節中的表,展示了一些公用接口。
JMS 公用接口 | PTP 域 | Pub/sub 域 |
---|---|---|
ConnectionFactory |
QueueConnectionFactory |
TopicConnectionFactory |
Connection |
QueueConnection |
TopicConnection |
Destination |
Queue |
Topic |
Session |
QueueSession |
TopicSession |
MessageProducer |
QueueSender |
TopicPublisher |
MessageConsumer |
QueueReceiver ,QueueBrowser |
TopicSubscriber |
統一有公用接口的域會導致繼承這些方法的一些特定於域的類不再適合它的域。如果在客戶機代碼中出現這種情況,JMS 提供者需要使用 IllegalStateException。
開發 JMS 程序 | 第 6 頁(共15 頁) |
一個典型的 JMS 程序要經過以下步驟才能開始產生和使用消息:
- 通過 JNDI 查詢
ConnectionFactory
。 - 通過 JNDI 查詢一個或者多個
Destination
。 - 用
ConnectionFactory
創建一個Connection
。 - 用
Connection
創建一個或者多個Session
。 - 用
Session
和Destination
創建所需要的MessageProducer
和MessageConsumer
。 - 啓動
Connection
。
這時,消息就可以開始流動,應用程序可以根據需要接收、處理和發送消息。 在後面幾節中,我們將開發 JMS 程序,您將會看到這些步驟的細節。
消息 | 第 7 頁(共15 頁) |
消息系統的核心當然是消息。JMS 爲不同類型的內容提供了幾種消息類型,但所有消息都是從 Message
接口派生出來的。
Message
分爲三個組成部分:
- header 是一組標準字段,客戶機和提供者都用它們來標識和路由消息。
- Properties 提供了一個給消息添加可選標題字段的實用工具。如果應用程序需要用標準標題字段沒有提供的方法對消息進行歸類或分類,那麼可以爲消息添加一個屬性來實現這種歸類和分類;提供了
set<Type>Property(...)
和get<Type>Property(...)
方法來設置和獲得各種 Java 類型的屬性,其中包括Object
。JMS 定義了提供者可以選擇性提供的一組標準屬性。 - 消息的 body 包含將 發送到接收應用程序的內容。每一個消息接口都專用於它所支持的內容類型。
header 字段 | 第 8 頁(共15 頁) |
下面列出了 Message
的每一個標題字段的名稱、它對應的 Java 類型和字段的描述:
JMSMessageID
——類型爲string
惟一標識提供者發送的每一條消息。這個字段是在發送過程中由提供者設置的,客戶機只能在消息發送後才能確定消息的
JMSMessageID
。JMSDestination
——類型爲Destination
消息發送的
Destination
,在發送過程中由提供者設置。JMSDeliveryMode
——類型爲int
包含值
DeliveryMode.PERSISTENT
或者DeliveryMode.NON_PERSISTENT
。持久性消息被傳輸並且只被傳輸一次,非持久性消息最多被傳輸一次。要知道“最多一次”包括根本不傳輸。非持久性消息在應用程序或者系統出故障時被提供者弄丟。因此要格外小心,確保持久性消息不受故障的影響。這比開銷通常被認爲是發送持久性消息方面的開銷,在決定消息的發送模式時,必須仔細考慮,在可靠性和性能之間進行權衡。JMSTimestamp
——類型爲long
提供者發送消息的時間,由提供者在發送過程中設置。
JMSExpiration
——類型爲long
消息失效的時間。這個值是在發送過程中計算的,是發送方法的生存時間(time-to-live)值和當前時間值的和。提供者不應發送過期的消息。值 0 表明消息不會過期。
JMSPriority
——類型爲int
消息的優先級,由提供者在發送過程中設置。優先級 0 的優先級最低,優先級 9 的優先級最高。
JMSCorrelationID
——類型爲string
通常用來鏈接響應消息與請求消息,由發送消息的 JMS 程序設置。響應來自另一個 JMS 程序的消息的 JMS 程序將正響應消息的
JMSMessageID
拷貝到這個字段中,這樣,正作出響應的程序就可以與它所發出的特定請求的響應相 關聯。JMSReplyTo
——類型爲Destination
請求程序用它來指出回覆消息應發送的地方,由發送消息的 JMS 程序設置。
JMSType
——類型爲string
JMS 程序用它來指出消息的類型。一些提供者維護着一個消息類型倉庫,並用該字段引用倉庫中的定義類型,在這裏,JMS 程序不應該使用這個字段。
JMSRedelivered
——類型爲boolean
指出消息被過早地發送給了 JMS 程序,程序不知道消息的接收者是誰;由提供者在接收過程中設置。
標準屬性 | 第 9 頁(共15 頁) |
下面列表給出了 Message
的每一個標準屬性的名稱、它對應的 Java 類型和該屬性的說明。提供者對標準屬性的支持是可選的。JMS 爲這些屬性和將來 JMS 定義的屬性保留了 “JMSX” 屬性名。
JMSXUserID
——類型爲string
發送消息的用戶的身份。
JMSXApplID
——類型爲string
發送消息的應用程序的身份。
JMSXDeliveryCount
——類型爲int
已經嘗試發送消息的次數。
JMSXGroupID
——類型爲string
該消息所屬的消息組的身份。
JMSXGroupSeq
——類型爲int
該消息在消息組中的序號。
JMSXProducerTXID
——類型爲string
生成該消息的事務的身份。
JMSXConsumerTXID
——類型爲string
使用該消息的事務的身份。
JMSXRcvTimestamp
——類型爲long
JMS 將消息發送給客戶的時間。
JMSXState
——類型爲int
提供者用它來維護消息的消息倉庫,通常,它與 JMS 生產者和客戶關係不大。
JMSX_<vendor_name>