Java 開發者和咨詢顧問Kyle Gabhart 解釋了為什么消息服務對于企業的體系結構來說是至關重要的,您的解決方案必須克服什么類型的障礙,以及 除了Java消息服務(Java Message Service ,JMS)之外,還有哪些替代的解決方案。在本文的結尾,他分析了三種可用的解決方案(簡單JMS客戶機(Simple JMS Client)、結合JMS使用的會話bean, 以及消息驅動bean),并且提供了一些特定的指導方針來衡量這些選項。
說到對消息傳遞解決方案的選擇,您可以像配手套那樣找到適合于企業的解決方案。您的消息傳遞框架必須能夠在一組應用和企業資源之間進行通信。而且,該消息傳遞框架必須快速、可靠地完成這一任務。此外,面對日復一日的騷擾和緊急情況,它必須表現得天衣無縫。
為了根據您的需求選擇適當的消息傳遞解決方案,首先應該對您企業當前的組成結構以及將來的發展趨勢有一個清醒的認識。此外,如果能夠透徹地理解消息傳遞框架在完成目標的過程中必須克服的障礙,那么對于解決方案的選擇將會很有幫助。最后,您要知道 可選擇的范圍:有哪些可用的技術,以及各種技術對于不同的環境和需求的適用情況如何。
在本期的J2EE 探索者中,我們將一一闡述以上要點。首先是對企業消息傳遞的概述,在此我們將著眼于消息傳遞在您企業中所扮演的角色,并在建立可靠的通信方面給出了一些挑戰。接著,我們將從體系結構的角度來快速 了解一下,在一個典型的企業網絡環境中,J2EE 消息傳遞技術如何與面向消息的中間件協同工作。然后,我們將針對Java消息服務(Java Message Service ,JMS)和J2EE的消息傳遞包展開更具體的討論。我們將分別論述三種類型的J2EE消息傳遞客戶機的基本目標和功能,而且您也可以了解到每種類型的 J2EE消息傳遞客戶機各自的優勢和劣勢所在。最后,我們將分析一些常見的消息傳遞場景和解決方案,這將有助于您為您的企業選擇最好的J2EE消息傳遞解決方案。
企業消息傳遞101
企業消息傳遞框架被設計用于使得一個或多個應用能夠克服各種障礙進行通信。常見的屏障包括:兩個系統同時運行(同步通信)的需求,多個應用獲取同一條消息(多重傳輸)的需求,大多數系統都彼此異構,以及網絡故障等。
M許多企業的體系結構依賴于面向消息的中間件系統(MOM)來為不同類型的系統提供消息通道。MOM為應用提供了一種公共的、可靠的方式,使這些應用能夠輕松地創建、交換和處理消息,而無需考慮消息傳遞客戶機的實現細節。消息被發送到服務器目的地和域 (domain),而不是發送到物理地址。消息傳遞客戶機只需簡單地聲明對某個特定的域和目的地感興趣,提供適當的安全性令牌(security token)以獲得訪問該域的權限,然后通過那個目的地與消息傳遞服務器進行交互。
從概念上來講,這與現實生活中真實郵件的傳遞方式沒什么不同。消息的發送方只負責使用正確的包裝,提供正確的地址,并附上適當的郵資。 郵局(這里是一個MOM系統)處理 與消息的安全可靠的傳遞相關的所有問題,而不 管出現在他們面前的任何障礙(機器故障,天氣惡劣,等等)。
在一個MOM系統中,客戶機之間的耦合性比較弱,這允許它們不必真正地全天“在線”便能維持服務的最佳質量。如果能夠去掉應用一直處于可用狀態這一需求,那么維護和伸縮性將變得更加易于管理。可以在一天中的任何時候將應用離線,更新應用,或者作為例行的維護工作刷新應用,而不必擔心會影響服務的質量。
Java 消息服務
MOM 服務器允許不同類型的系統交換消息,但是每個MOM供應商都有其特有的處理消息的API。這種標準化的缺乏對于Java技術開發范例來說是不可接受的。為了充分利用已有的MOM基礎設施,同時又不失標準化,J2EE平臺提供了JMS。
Java 標準化 為了提供平臺無關的和供應商無關的解決方案,所有Java技術都可以分成兩個部分:
- 一份(或一套)定義該項技術的 規范說明書,指出了開發者和實現該技術的工具供應商的目標和責任。
- 一套中立接口,作為應用開發者與工具供應商之間的契約。
不管您使用的是何種Java技術,您首先要編寫使用了技術規范中提供的接口的應用組件,然后在運行時提供某一特定供應商對這些接口的實現。在J2EE中,企業消息傳遞的規范和API是JMS。
|
JMS 定義了在Java企業系統中傳遞消息的規則,并且聲明了一些方便應用組件和消息傳遞系統(通常是MOM)之間的消息交換的接口。JMS客戶機向MOM服務器上的目的地開放連接,然后在那個目的地上發送和接收消息。JMS卸下了 保證傳送(guaranteed delivery)、消息通知(message notification)、消息耐久性(message durability)以及消息傳遞系統中所有底層網絡和路由問題的負擔。JMS和MOM能夠很好地協同工作,因為它們都劃清了消息傳遞客戶機和服務器之間的責任界限。
消息傳遞的類型
JMS 支持兩種基本的消息傳遞機制。第一種機制是點到點的消息傳遞(point-to-point messaging),在這種機制下,消息由一個發布者(發送方)發送,由訂閱者(接收方)接收。另一種機制是發布-訂閱式的消息傳遞(publish- subscribe messaging),在這種機制下,消息由一個或多個發布者發送,由一個或多個訂閱者接收。盡管這兩種機制是JMS的實際基礎,很多人還是按照三種消息傳遞模型來看待這項技術:
- 一對一的消息傳遞(One-to-one messaging )是一種點到點的模型。消息由一個JMS客戶機(發布者)發送到服務器上的一個目的地,即一個隊列(queue)。而另一個JMS客戶機(訂閱者)則可以訪問這個隊列,并從該服務器獲取這條消息。在隊列中可以存放多條消息,但每次只能獲取一條消息。
- 一對多的消息傳遞(One-to-many messaging)是一種發布-訂閱模型。這里仍然是由一個JMS客戶機將一條消息發布到服務器上的一個目的地上,但是這次這個目的地叫做一個主題(topic)。這里關鍵的不同在于放在一個主題中的消息包括了一個參數,這個參數定義了該消息的耐久性(它能夠在服務器上等待訂閱者多長時間)。該消息將一直維持在主題中,直到這個主題的所有訂閱者都取走了該消息的一個副本,或者該消息的耐久性時間已到期,不管發生的是上述中的哪種情況,該消息都將被從這個主題中刪除。
- 多對多的消息傳遞(Many-to-many messaging),這也是一種發布-訂閱模型,同時還擴展了一對多的消息傳遞模型。除了支持多個訂閱者外,該模型還支持一個主題有多個發布者。多對多消息傳遞的一個很好的例子就是e-mail listserve:多個發布者可以將多條消息投遞到一個主題,而所有的訂閱者將獲取每一條消息。
JMS消息的結構相當直觀。其中有一個部分(section)用于路由、尋址和消息識別;還有一個可選的部分,在這個部分中可以傳遞一些特定于應用(application-specific)的參數;第三個 部分存放的是消息的有效負荷(文本 、字節、值映射(value map)、對象,等等)。這三個部分分別被稱為頭部、屬性和主體,如圖 1 所示。
圖 1. JMS 消息結構

您所使用的消息傳遞模型的類型取決于您企業的需要。在一個企業中同時使用不止一個的消息傳遞策略并不少見。在后面的一些小節中,我們將研究一下用于Java 平臺的三種JMS解決方案:簡單JMS客戶機,結合JMS使用的會話bean,以及消息驅動bean。我們將重新回顧每種類型,它們各自的優點和缺點,以及它們對不同企業場景的適用情況。
簡單JMS客戶機
盡管JMS是與Java 2 Enterprise Edition一起發布的一種企業級的技術,您仍可以輕松地將一個標準Java客戶機轉換成一個支持JMS的應用。將企業消息傳遞功能添加到Java applet、命令行應用程序、Swing應用程序或者Java WebStart都非常簡單。您只需簡單地將少量方法調用添加到J2SE應用代碼中,然后將一個包含了JNDI(也是J2EE的一部分)的接口和實現類的JAR文件添加到類路徑(classpath)中。如果您已經在客戶機上裝載了這個JAR文件,并且將它添加到了您的應用的類路徑中,那么您就可以使用JNDI來訪問JMS提供者(參見下面的參考資料 ,以獲得關于JMS消息傳遞的更多信息的鏈接)。
簡單JMS 客戶機的優點和缺點
簡單JMS 客戶機方法有許多優點,最明顯的優點就是它的簡單性和普遍性。所有的J2SE應用都可以毫不費力地擴展為可以與一個JMS消息傳遞系統進行交互。此外,使用JMS的新應用部署起來只需對客戶端進行少量的配置,甚至不需要配置。簡單JMS客戶機是對幾乎任何Java體系結構的簡單、靈活和輕量級的一個擴展。
從消極的方面來看,我們會遇到安全性、事務處理以及可伸縮性等問題。對于一個簡單JMS客戶機,您只能選擇將安全性和事務處理外包給某個供應商,也就是說,這些問題將是以一種特定于供應商的方式來處理的。如果您的簡單JMS客戶機既要處理傳進來的消息,又要發送消息,那么就會碰到可伸縮性問題。JMS沒有能夠一次處理多于一個傳進來的請求的內建機制。為了支持并發請求,您需要擴展JMS客戶機,使其產生多個線程,或者啟動多個JVM實例,讓這些線程或實例各自運行應用。此外,還需要將JMS提供者配置為在一些適當的目的地上可以有多個訂閱者。這時,您(或者您的開發小組)就會質疑簡單JMS客戶機解決方案是否真的具有簡單性。
會話bean與JMS
將會話bean與JMS結合起來使用是一種可行的面向企業的解決方案。會話bean被設計用來履行對業務服務的請求。必須查詢企業消息傳遞系統來履行這樣的一個請求,就這一點來說,企業消息傳遞系統可以由一個會話bean透明地來訪問。使用會話bean作為JMS客戶機還允許將JMS通信合并到一個大型企業事務的上下文環境中。例如,可以建立一個J2EE事務來從一個JMS提供者那里獲取一條消息,從該消息中提取數據,并嘗試更新數據庫。如果更新操作失敗并且事務回滾 (rollback),則再發送一條消息到一個單獨的目的地上的JMS提供者那里,同時給出對事務失敗的原因的描述。
企業JavaBeans 技術使用資源管理器連接工廠來訪問額外容器(extra-container )資源。這些資源是標準的企業組件,但不是J2EE容器的核心部分,它們包括數據源、JMS會話、JavaMail會話、URL連接以及Java連接器體系結構( Java Connector Architecture ,JCA)適配器。資源管理器是J2EE容器的一個組件,它管理著某一特定類型的資源的整個生命周期,這些資源包括連接池、事務支持以及實現實際連接所必需的任何網絡協議。
企業bean通過三個步驟來獲得一個JMS會話的連接:通過JNDI查找獲得一個連接工廠引用,通過工廠引用獲得一個連接,然后以一種常規的JMS的方式使用主題或者隊列連接對象。因為JMS必須有遵從J2EE規范的應用服務器的支持,因此不再需要附加的庫或者組件。
JMS會話bean 的優點和缺點
將JMS和會話bean結合起來使用,這在企業功能性方面是一個進步,而在簡單性和靈活性方面卻又是一個退步。通過使用會話bean,應用開發者可以訪問 EJB容器所提供的整個范圍的J2EE功能,包括JNDI、宣告式事務語義、自動并發支持、資源管理、宣告式安全性以及對諸如實體bean、數據源、 JavaMail和JCA適配器之類的企業資源的訪問。從消息傳遞的立場來看(跟MDB不一樣),會話bean與JMS的聯手并沒有對您的bean所能訪問的主題和隊列強加任何數量上的限制。
作為增強企業特性的代價,您犧牲了簡單性,客戶機占用空間(client footprint)也不再像以前那么小了,而且也沒有了異步性。前兩項損失倒沒什么好奇怪的,如果您已經關注探索者 系列有一段時間了,那么您就更能理解這一點。會話bean要求有一個成熟的J2EE EJB容器,這讓您的開發小組(針對EJB開發而言)和您的整個系統體系結構(針對客戶機占用空間而言)背上了沉重的包袱。
異步性是使用像JMS這樣的企業消息傳遞技術的主要優勢之一,而且,在取得這一優勢的同時它并沒有失去什么。有了JMS,消息傳遞客戶機可以通過提供者發送消息,消息發送出去之后便可以離線,而讓提供者從容地傳送這條消息。接收消息的客戶機可以周期性地上線并檢查新的消息,或者也可以設立一個偵聽器組件,令其一直處于在線狀態以等待來自提供者的消息。會話bean是同步的,因而不能支持“一直在線(always-on)”偵聽器組件。與前一種客戶機不同,同步的Java客戶機必須調用一個會話bean方法。然后由該會話bean方法打開與一個消息傳遞提供者的連接,以便發送和接收消息。
消息驅動bean
EJB 2.0 規范定義了一種新的企業bean,以期彌補其他四種類型的企業bean(兩種會話bean和兩種實體bean)的不足。這種新的bean就是消息驅動bean(message-driven bean,MDB),人們期望用它來提供可重用的消息傳遞組件,以便利用已有的在J2EE應用服務器方面的投資,尤其是利用已有的EJB技術。
MDB 只能通過一條JMS消息異步地進行調用。因此,它并不具有其他bean所具有的本地和遠程接口。相反,MDB實現兩種特殊的接口:一個與EJB容器之間的接口(javax.ejb.MessageDrivenBean),以及一個消息傳遞接口(javax.jms.MessageListener)。作為一種成熟的JMS客戶機,MDB通過一個MOM服務器既可以發送消息,又可以接收消息。作為一種企業bean,MDB由容器來管理,并且通過一個EJB部署描述符進行宣告式的配置。
MDB 的優點和缺點
MDB允許開發者利用已有的在EJB技術方面的投資,但是仍然可以將這些投資整合到一個異步消息傳遞的上下文環境中。例如,JMS客戶機可以發送一條消息給一個MDB(該MDB一直在線等待傳進來的消息),而后者可以訪問一個會話bean或者一些實體bean。通過這種方式,MDB可以被用作一種異步包裝器,提供對業務流程的訪問途徑,而之前這些業務流程只能通過一個同步的RMI/IIOP調用來訪問。
消息驅動bean本身也是一種強大的消息傳遞解決方案。由于MDB被專門設計用來作為消息的消費者,并且仍然是由EJB容器管理的,因此它們在可伸縮性方面提供了巨大的優勢。由于消息bean是無狀態的,并且由容器進行管理,因此它們并發地發送和接收消息(容器只是簡單地將另一個bean從池中提出)。這一點,加上EJB應用服務器所固有的可伸縮性,構成了一種極其健壯的、可伸縮的企業消息傳遞解決方案。
另一方面,MDB相對來說還是一種很新鮮的事物,沒有經過很多的檢驗。因而,并不是所有的J2EE供應商都支持它們,即使是支持MDB的那些供應商也只是最近才實現它們的。可以預見,MDB的不成熟意味著 供應商實現在穩定性和可靠性方面還有一段很長的路要走。而且,MDB社區也需要經歷更多的錘煉,以獲得一套成形的使用MDB的最佳實踐。
拋開MDB的相對不成熟性不提,理解它是為專門的目的而設計的(即作為JMS消息的消費者)十分重要。MDB只能通過JMS消息來調用,其他方式都不管用。這意味著它們作為消息的消費者非常理想,但未必適合作為消息的生產者。消息驅動bean當然可以發送消息,但前提是它首先要讓一條傳進來的請求調用它。而且,當前設計的MDB只能映射到單個的目的地。它們只能在那個目的地上偵聽消息。這一限制在以后的版本中可以改變,但目前您只能為每個您想偵聽的目的地定義一個MDB。
消息傳遞解決方案指導方針
如前所述,選擇適當的解決方案時,大部分要做的工作就是衡量您企業的特定需求,包括目前的需求和可預見的將來的需求。如果能記住多種企業消息傳遞解決方案可以結合使用,那么也會很有幫助。在下一節,我們將看一些常見的消息傳遞場景和每個場景潛在的JMS解決方案。當您為您的企業選擇適當的消息傳遞技術,或者混合使用多種技術時,這些內容可以 提供一般的指導方針。
從一個組件訪問多個主題和隊列
如果您的業務流程規定了消息目的地只能有條件地訪問(換句話說,如果x<5,則訪問主題A,如果x>5,則訪問主題B),那么您將不能使用 MDB。不過,您可以使用一個簡單JMS客戶機,或者將會話bean與JMS結合起來使用。為了在這兩種選擇之間作出決定,您必須在簡單JMS客戶機的輕量級特性(特別適合于applet、Swing應用程序和獨立的控制臺應用程序)以及J2EE容器的健壯性(包括透明的事務性支持、宣告式安全性和其他EJB型資源管理功能)之間進行權衡。
異步地訪問會話bean和實體bean
有兩種方式來處理這一場景。比較明顯的一種方式就是使用一個消息驅動bean,但前提是您的供應商支持MDB技術。MDB被設計用來消費異步消息并代表消息發送方訪問企業功能性。此外,應用服務器可以維護一個MDB的多個實例,來處理并發的服務請求。如果您不能使用MDB,您可以創建一個簡單JMS客戶機,以此來作為一個偵聽器。當收到一條消息時,該客戶機便可以與應用服務器建立一個同步的RMI連接,并按照常規的方式調用會話bean或者實體bean。不過,MDB是更值得推薦的解決方案。
構建盡可能瘦的JMS客戶機
在這一方面,簡單JMS客戶機顯然是贏家。如果對您來說更重要的是提供一個輕量級的消息傳遞客戶機,而不是擁有像會話bean這樣的J2EE客戶機的可伸縮性和健壯性,那么簡單JMS是 正確的選擇。無論是會話bean與JMS的組合,還是MDB,兩者都需要一個J2EE應用服務器,這使得兩種選擇都不適合瘦客戶機實現。
并發地發送和接收消息
這里惟一合適的選擇是使用消息驅動bean。消息驅動bean是專門為這一場景量身定做的。從技術上講,簡單JMS客戶機也可以利用多線程技術來提供類似的支持,但這種解決方案開發起來很復雜,并且最后開發出來的東西并沒有很好的可伸縮性。
將消息傳遞合并到J2EE過程中
您或許已經在J2EE體系結構中有所投入,并且認識到將企業消息傳遞合并到這些J2EE過程中的需要。在大多數情況下,您最好的解決方案是將會話bean 與JMS資源連接結合起來使用。您可以采用已有的會話bean來訪問一個或多個主題和隊列,而不必重建整個基礎設施。這些會話bean將繼續履行傳統的對業務服務的請求,并且還 擔負起了消息傳遞的任務。在某些情況下,將您已有的業務服務暴露給一個JMS客戶機是有好處的,這從前面的討論中也可以發現。
結束語
就今天技術前景的多樣性和日趨于異步的特點來說,消息傳遞是一種激動人心的、日益流行的解決方案。Java 消息服務提供了一種獨立于供應商和平臺的媒介,通過使用企業消息傳遞將多個系統系在一起。在本文中,我們簡要地瀏覽了企業消息傳遞和JMS,并且給出了一些指導方針,以方便您選擇最適合您企業的解決方案。