它是Java 消息服務
Java 消息服務是 J2EE (Java 2 Enterprise Edition) 套件的一部分,它提供了標準 API,Java 開發人員可以使用這些 API 來訪問企業消息系統的共同特性。JMS 支持發佈/訂閱和點對點模型,並允許創建由任意 Java 對象組成的消息類型。
體系架構
JMS有以下元素組成。
JMS提供者
連接面向消息中間件的,JMS接口的一個實現。提供者可以是Java平臺的JMS實現,也可以是非Java平臺的面向消息中間件的適配器。
JMS客戶
生產或消費消息的基於Java的應用程序或對象。
JMS生產者
創建併發送消息的JMS客戶。
JMS消費者
接收消息的JMS客戶。
JMS消息
包括可以在JMS客戶之間傳遞的數據的對象
JMS隊列
一個容納那些被髮送的等待閱讀的消息的區域。隊列暗示,這些消息將按照順序發送。一旦一個消息被閱讀,該消息將被從隊列中移走。
JMS主題
一種支持發送消息給多個訂閱者的機制。
JMS模型
Java消息服務應用程序結構支持兩種模型:
點對點或隊列模型
發佈者/訂閱者模型
在點對點或隊列模型下,一個生產者向一個特定的隊列發佈消息,一個消費者從該隊列中讀取消息。這裏,生產者知道消費者的隊列,並直接將消息發送到消費者的隊列。這種模式被概括爲:
只有一個消費者將獲得消息
生產者不需要在接收者消費該消息期間處於運行狀態,接收者也同樣不需要在消息發送時處於運行狀態。
每一個成功處理的消息都由接收者簽收
發佈者/訂閱者模型支持向一個特定的消息主題發佈消息。0或多個訂閱者可能對接收來自特定消息主題的消息感興趣。在這種模型下,發佈者和訂閱者彼此不知道對方。這種模式好比是匿名公告板。這種模式被概括爲:
多個消費者可以獲得消息
在發佈者和訂閱者之間存在時間依賴性。發佈者需要建立一個訂閱(subscription),以便客戶能夠購訂閱。訂閱者必須保持持續的活動狀態以接收消息,除非訂閱者建立了持久的訂閱。在那種情況下,在訂閱者未連接時發佈的消息將在訂閱者重新連接時重新發布。
使用Java語言,JMS提供了將應用與提供數據的傳輸層相分離的方式。同一組Java類可以通過JNDI中關於提供者的信息,連接不同的JMS提供者。這一組類首先使用一個連接工廠以連接到隊列或主題,然後發送或發佈消息。在接收端,客戶接收或訂閱這些消息
傳遞消息方式
JMS現在有兩種傳遞消息的方式。標記爲NON_PERSISTENT的消息最多投遞一次,而標記爲PERSISTENT的消息將使用暫存後再轉送的機理投遞。如果一個JMS服務離線,那麼持久性消息不會丟失但是得等到這個服務恢復聯機時纔會被傳遞。所以默認的消息傳遞方式是非持久性的。即使使用非持久性消息可能降低內務和需要的存儲器,並且這種傳遞方式只有當你不需要接收所有的消息時才使用。
雖然JMS規範並不需要JMS供應商實現消息的優先級路線,但是它需要遞送加快的消息優先於普通級別的消息。JMS定義了從0到9的優先級路線級別,0是最低的優先級而9則是最高的。更特殊的是0到4是正常優先級的變化幅度,而5到9是加快的優先級的變化幅度。舉例來說: topicPublisher.publish (message, DeliveryMode.PERSISTENT, 8, 10000); //Pub-Sub 或 queueSender.send(message,DeliveryMode.PERSISTENT, 8, 10000);//P2P 這個代碼片斷,有兩種消息模型,映射遞送方式是持久的,優先級爲加快型,生存週期是10000 (以毫秒度量 )。如果生存週期設置爲零,這則消息將永遠不會過期。當消息需要時間限制否則將使其無效時,設置生存週期是有用的。
JMS定義了五種不同的消息正文格式,以及調用的消息類型,允許你發送並接收以一些不同形式的數據,提供現有消息格式的一些級別的兼容性。
· StreamMessage -- Java原始值的數據流
· MapMessage--一套名稱-值對
· TextMessage--一個字符串對象
· ObjectMessage--一個序列化的 Java對象
· BytesMessage--一個未解釋字節的數據流
JMS應用程序接口
ConnectionFactory 接口(連接工廠)
用戶用來創建到JMS提供者的連接的被管對象。JMS客戶通過可移植的接口訪問連接,這樣當下層的實現改變時,代碼不需要進行修改。 管理員在JNDI名字空間中配置連接工廠,這樣,JMS客戶才能夠查找到它們。根據消息類型的不同,用戶將使用隊列連接工廠,或者主題連接工廠。
Connection 接口(連接)
連接代表了應用程序和消息服務器之間的通信鏈路。在獲得了連接工廠後,就可以創建一個與JMS提供者的連接。根據不同的連接類型,連接允許用戶創建會話,以發送和接收隊列和主題到目標。
Destination 接口(目標)
目標是一個包裝了消息目標標識符的被管對象,消息目標是指消息發佈和接收的地點,或者是隊列,或者是主題。JMS管理員創建這些對象,然後用戶通過JNDI發現它們。和連接工廠一樣,管理員可以創建兩種類型的目標,點對點模型的隊列,以及發佈者/訂閱者模型的主題。
MessageConsumer 接口(消息消費者)
由會話創建的對象,用於接收發送到目標的消息。消費者可以同步地(阻塞模式),或異步(非阻塞)接收隊列和主題類型的消息。
MessageProducer 接口(消息生產者)
由會話創建的對象,用於發送消息到目標。用戶可以創建某個目標的發送者,也可以創建一個通用的發送者,在發送消息時指定目標。
Message 接口(消息)
是在消費者和生產者之間傳送的對象,也就是說從一個應用程序創送到另一個應用程序。一個消息有三個主要部分:
消息頭(必須):包含用於識別和爲消息尋找路由的操作設置。
一組消息屬性(可選):包含額外的屬性,支持其他提供者和用戶的兼容。可以創建定製的字段和過濾器(消息選擇器)。
一個消息體(可選):允許用戶創建五種類型的消息(文本消息,映射消息,字節消息,流消息和對象消息)。
消息接口非常靈活,並提供了許多方式來定製消息的內容。
Session 接口(會話)
表示一個單線程的上下文,用於發送和接收消息。由於會話是單線程的,所以消息是連續的,就是說消息是按照發送的順序一個一個接收的。會話的好處是它支持事務。如果用戶選擇了事務支持,會話上下文將保存一組消息,直到事務被提交才發送這些消息。在提交事務之前,用戶可以使用回滾操作取消這些消息。一個會話允許用戶創建消息生產者來發送消息,創建消息消費者來接收消息。
設計目標
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 消息由三部分組成:
消息標題 :用於消息標識。例如,標題用於確定指定的消息是否適合於“訂閱者”。
屬性 :用於特定於應用程序、特定於提供商及可選的標題字段。
消息體 :保存消息的內容。支持幾種格式,其中包括:TextMessages——用於包裝簡單的 String; 和 ObjectMessages——用於包裝任意的 Java 對象(它們必須是可序列化的)。也支持其他的格式。
TextMessages
TextMessage 用於包裝簡單的 String 對象。在只傳遞字符串的情形下,這是有用的。期望許多消息傳遞系統將以 XML 爲基礎,TextMessages 是它們的自然容器。
創建 TextMessage 對象是簡單的,如下面兩行代碼所指出的那樣:
TextMessage message =
session.createMessage();
message.setText("hello world");
以這種方式創建的 TextMessage 準備發佈到消息傳遞系統中。
ObjectMessages
顧名思義,ObjectMessage 是包裝了 Java 對象的消息。任何可序列化的 Java 對象均可用作 ObjectMessage。如果多個對象必須在單個消息中傳輸,那麼可以使用包含幾個可序列化對象的 Collection 對象(比如 List 或 Set)。
下面展示瞭如何創建 Object 消息:
ObjectMessage message = session.createObjectMessage();
message.setObject(myObject);
構建 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 的消息傳遞系統。
-----------------------------------------------------------------------
MessageDrivenBean 在 EJB 2.0 中,對規範的一個基礎性更改是添加了一種全新的企業級 bean 類型,即 MessageDrivenBean。MessageDrivenBean 專門設計來處理入網的 JMS 消息。對於許多開發人員來說,JMS 是一種新的範例,所以本文將花一些時間逐步說明對 JMS 的理解,以及它們在 EJB 2.0 中的用法。
消息中間件 |