如今,大多數計算環境更多地是由不同平台組成,而不是固守任何一個平台。 Java 消息服務 (JMS) ,與可擴展標記語言 (XML) 一起,滿足了這種異構環境集成的願望。這篇文章演示了如何使用 JMS 來創建基於 XML 的消息並將這些消息同樣分發到 Java 和非 Java 應用程序。
經過幾年構建、擴展和維護龐大的分布式應用之後,程序員逐步體會到平台無關的行為和平台無關的數據的好處了。
Java 編程語言已經向滿足平台無關的行為(盡管例如 TCL 這樣的腳本語言在一段或更長時間內還受到關注)的需要邁進了一步。而且 XML(可擴展標記語言)正在成為開放、平台無關的數據解決方案的中堅力量。
本文演示了在與 Java 消息服務 (JMS) 一起使用的情況下,XML 如何滿足平台無關的數據的願望。
消息傳遞將它們聯系在一起
JMS 為消息服務定義了通用 Java 語言接口。它支持最常見的消息傳遞模型(包括發布/訂閱和點到點)。
首先將平台無關的數據與 Java 技術放在一段文字中提及看起來比較奇怪。然而,既然JMS是一種基於 Java(因此是平台無關的)的技術,我們為什麼在使用 JMS 時需要平台無關的數據呢?
答案來源於經常使用消息傳遞的環境。消息傳遞的一個最大優點體現在應用集成領域。被集成的應用多半不全是 Java 應用。
在這種情況下 JMS 非常理想,因為它是一種接口規范 -- 而不是實現。這意味著JMS位於已經有了相當的應用現有技術的上面一層。(當然,所有 Java 實現也能利用這種 JMS 和 XML 的解決方案。)
圖 1. 位於專有消息服務上層的 JMS
圖 1 說明了這樣一種環境。非 Java 應用與專用消息服務直接進行通信。Java 應用通過 JMS 通信。每一樣是無縫的,對嗎?
但不完全是。數據仍然是一個需要解決的問題。
平台無關的數據解決了問題
請考慮 JMS 的五種消息類型。JMS 提供了三種結構化或半結構化的消息類型(MapMessage、ObjectMessage 和 StreamMessage)以及兩種非結構化的或自由格式的消息類型(TextMessage 和 BytesMessage)。
結構化的消息格式只代表了眾多處理結構化數據方法中的少數幾種(只有映射表、序列化對象和數據元素流是直接表示的)。更重要的是,它們引發了與非 Java 應用交互操作的問題。轉換或映射,特別是在轉換涉及到序列化的類時是如何實現的呢?
非結構化的消息格式似乎能夠更好地進行交互操作,但這僅僅是因為它們在消息上很少利用結構。然而這個很小的便利卻為每個接受者加重了語法分析和確認的負擔。
XML 減輕了這種負擔。它為豐富的功能性數據結構提供了清晰的標准化途徑,並通過越來越多的工具來支撐它,這些工具是用來執行語法分析和確認這些費力的工作的。
通過在環節中使用 XML,每一樣都是無縫的。
代碼
以下兩段代碼說明了如何傳送 XML 消息。因為 XML 基本上是文本,所以它在 TextMessage 實例的主體中傳送。兩個示例都假設有 XMLValidator 類存在。這個類是許多基於 Java 的 XML 語法分析和確認工具之一的一個簡單封裝。
發送方是非常簡單的。清單 1 中的代碼說明了如何找到 Queue 和 QueueConnectionFactory、如何創建連接和會話、如何將 XML 填充到 TextMessage,以及如何將消息發送給隊列。
清單 1. 發送 XML 消息的示例
public
static
void
send(
String stringQueue,
String stringQueueConnectionFactory,
XMLValidator XMLvalidator,
String stringXML)
throws
NamingException,
JMSException,
XMLValidationException {
//在一個名為JNDI和目錄服務中查找Queue 和 QueueConnection 類廠,或者直接創建它們
Context context = new InitialContext();
Queue queue = null;
queue = (Queue)context.lookup(stringQueue);
QueueConnectionFactory queueconnectionfactory = null;
queueconnectionfactory =
(QueueConnectionFactory)context.lookup(stringQueueConnectionFactory);
QueueConnection queueconnection = null;
queueconnection = queueconnectionfactory.createQueueConnection();
QueueSession queuesession = null;
queuesession =
queueconnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// 創建 QueueSender.
QueueSender queuesender = null;
queuesender = queuesession.createSender(queue);
//首先在XML中創建一個TextMessage,如果XML是通過用戶輸入創建的,那麼驗證XML的合法性是非常必要的。然後發送它。
xmlvalidator.validate(stringXML);
TextMessage textmessage;
textmessage = queuesession.createTextMessage();
textmessage.setText(stringXML);
queuesender.send(textmessage);
}
在接收方有許多事要做(見清單 2)。接收了 TextMessage 後,代碼抽取 XML 並驗證它。確認過程根據文檔類型定義 (DTD) 來檢查 XML,DTD 可以是 XML 的一部分,也可以在它的外部。
如果 DTD 是在外部存儲的,您很可能要面臨創建和維護企業范圍的 DTD 資源庫。資源庫嚴格定義了共同參加的企業應用程序可以交換的消息的結構。
現在,TextMessage 成為非常有條理、定義明確的消息的“載體”,Java 和非 Java 應用程序都可以理解。
清單 2. 接收 XML 消息的示例
public
static
String
receive(
String stringQueue,
String stringQueueConnectionFactory,
XMLValidator XMLvalidator)
throws
NamingException,
JMSException,
XMLValidationException {
//在一個名為JNDI和目錄服務中查找Queue 和 QueueConnection 類廠,或者直接創建它們
Context context = new InitialContext();
Queue queue = null;
queue = (Queue)context.lookup(stringQueue);
QueueConnectionFactory queueconnectionfactory = null;
queueconnectionfactory =
(QueueConnectionFactory)context.lookup(stringQueueConnectionFactory);
QueueConnection queueconnection = null;
queueconnection = queueconnectionfactory.createQueueConnection();
QueueSession queuesession = null;
queuesession =
queueconnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// 創建 QueueReceiver.
QueueReceiver queuereceiver = null;
queuereceiver = queuesession.createReceiver(queue);
//接受一個TextMessage, 提取其中的XML,
//並在返回之前驗證它。在驗證XML和返回之前,將XML轉換成一個DOM數或者其它的表示方法也是可以的。
TextMessage textmessage;
textmessage = (TextMessage)queuereceiver.receive();
String stringXML = textmessage.getText();
xmlvalidator.validate(stringXML);
return stringXML;
}
結束語
似乎大家有了共識,認為面向消息的中間件(JMS 是其一部分)和 XML 屬於一起的。我希望我的論述為這個提法增添了說服力。它並不是那麼出人意外的。XML 文檔是真實的消息 -- 它們是結構化的,但仍具有相當的靈活性。另外,MOM,和 XML 一樣,擅長集成異構應用程序。