級(jí)別: 初級(jí)
Sing Li (westmakaha@yahoo.com), 作者
2005 年 8 月 08 日
Apache Geronimo 是具有開(kāi)放架構(gòu)且功能強(qiáng)大的開(kāi)源 Java? 2 平臺(tái)企業(yè)版 (J2EE) 1.4 服務(wù)器容器,可以承載多種現(xiàn)有的服務(wù)器和服務(wù)。ActiveMQ 是一個(gè)經(jīng)驗(yàn)證的最佳開(kāi)源 Java 消息服務(wù) (JMS) 引擎,該引擎還附帶一個(gè)精巧多用的功能和連接選項(xiàng)庫(kù)。二者結(jié)合使用時(shí),會(huì)發(fā)生奇跡般的效果!Sing Li 將為您介紹這種共存關(guān)系,并提供示例代碼,幫助您開(kāi)始編寫(xiě) JMS 應(yīng)用程序并立即使用 Geronimo 創(chuàng)建 Message-Driven Beans (MDB)。
JMS API 是 J2EE 平臺(tái)的整體組成部分,允許在松耦合組件之間進(jìn)行基于消息的通信。通過(guò)客戶機(jī)、Web 層組件、業(yè)務(wù)層企業(yè) JavaBeans (EJB) 和企業(yè)信息系統(tǒng) (EIS) 層服務(wù)之間的 J2EE 堆??梢园l(fā)送和接收消息。這些消息是異步發(fā)送的,消息發(fā)出后,發(fā)送方能夠繼續(xù)使用其他應(yīng)用程序邏輯,消息代理 (message broker) 負(fù)責(zé)代表發(fā)送方傳遞消息。消息可以在特定的端點(diǎn)(發(fā)送方和接收方)之間發(fā)送和接收,或通過(guò)公共/訂閱交互模式在生產(chǎn)者與消費(fèi)者之間進(jìn)行匿名傳遞。在 J2EE 架構(gòu)內(nèi)部,通過(guò) JMS 進(jìn)行通信的組件可以使用容器提供的安全和事物處理功能。Geronimo 通過(guò)集成名為 ActiveMQ 的開(kāi)源項(xiàng)目來(lái)支持這個(gè)重要的 API。
本文將探討如何在 Geronimo 中集成 ActiveMQ。您將了解 Geronimo 如何從集成中受益,以及 ActiveMQ 功能如何通過(guò)駐留在 Geronimo 內(nèi)部得到增強(qiáng)??梢詮谋疚南螺d一個(gè)操作示例,該示例揭示了如何對(duì)通過(guò) JMS 進(jìn)行通信的客戶機(jī)和組件進(jìn)行編碼。另一個(gè)示例顯示了如何在 Geronimo 內(nèi)部創(chuàng)建萬(wàn)能的 MDB。
ActiveMQ:最佳的開(kāi)源 JMS 實(shí)現(xiàn)
在 JMS 術(shù)語(yǔ)中,ActiveMQ 是一個(gè)成熟而又功能豐富的 JMS 服務(wù)器或消息代理。位于 Codehaus(請(qǐng)參閱 參考資料)中的 ActiveMQ 支持許多不同的傳輸(如 TCP、SSL、UDP、多點(diǎn)傳送、內(nèi)部 JVM 和 NIO)和客戶機(jī)交互(如推、拉和發(fā)行/訂閱)。以一定規(guī)模的現(xiàn)有用戶為基礎(chǔ),ActiveMQ 服務(wù)器完全可以獨(dú)立工作,而不依賴任何容器(J2EE 或其他容器),它還可以與 J2EE 服務(wù)器主機(jī)(如 Geronimo)結(jié)合使用。
當(dāng) ActiveMQ 在 Geronimo 中運(yùn)行時(shí),會(huì)對(duì) MDB 提供支持,即使用 JMS 消息的 EJB。JMS 的異步特性允許容器隨需應(yīng)變地激活 MDB,代表客戶機(jī)執(zhí)行 J2EE 服務(wù)器內(nèi)的任務(wù)。Geronimo 會(huì)從 ActiveMQ 的富客戶機(jī)支持中得到很大好處。與會(huì)話或?qū)嶓w EJB 不同,MDB 不是通過(guò)嚴(yán)格的 EJB 界面調(diào)用的。相反,客戶機(jī)只需將 JMS 消息發(fā)送到目標(biāo),便可以調(diào)用 MDB 服務(wù)。這樣大大簡(jiǎn)化了使用基于 EJB 服務(wù)的客戶機(jī)的編碼過(guò)程。事實(shí)上,Geronimo 繼承了向非 J2EE 客戶機(jī)提供服務(wù)的功能 —— 這些功能受到獨(dú)立 ActiveMQ 服務(wù)器的支持。
在 GBean 中包裝 ActiveMQ 消息代理
ActiveMQ 消息代理被設(shè)計(jì)成可嵌入式的。Geronimo 充分利用了這一功能。通過(guò)提供包裝已嵌入消息代理的 GBean 容器,可以創(chuàng)建 ActiveMQContainerGBean。ActiveMQ 消息代理的其他組件也被包裝到 GBeans 中,您很快就會(huì)看到這種情形。圖 1 說(shuō)明了 ActiveMQContainerGBean 是如何嵌入 ActiveMQ 消息代理的。
圖 1. ActiveMQContainerGBean
通過(guò)將 ActiveMQ 消息代理包裝到 GBean 中,該代理的生命周期由 Geronimo 管理。具體地說(shuō),您可以使用 Geronimo 部署程序和管理工具部署、啟動(dòng)和管理 ActiveMQ 消息代理實(shí)例。消息代理的可配置屬性是作為 GBean 屬性公開(kāi)的。在 圖 1 中,ActiveMQContainerGBean 對(duì) ActiveMQ 消息代理進(jìn)行了包裝,并提供了生活周期管理和配置服務(wù)。除了提供生命周期和配置支持外,Geronimo 還對(duì)持久消息提供持久支持。目前的 ActiveMQ 服務(wù)器配置使用默認(rèn) Derby RDBMS 實(shí)例來(lái)處理持久消息。
由 Geronimo 提供的默認(rèn) J2EE 服務(wù)器集集成了一個(gè) ActiveMQ 消息代理實(shí)例。這個(gè)集合在服務(wù)器啟動(dòng)時(shí)啟動(dòng)消息代理,通常使用的命令行如下:
要查看此實(shí)例是如何配置的,可以檢查 Geronimo 源代碼分配的計(jì)劃目錄中的 system-activemq-plan.xml 部署計(jì)劃。您將看到 ActiveMQContainerGBean 和其他相關(guān)的 ActiveMQ 組件是如何配置的。清單 1 顯示了此部署計(jì)劃中的相關(guān)字段。
清單 1. 在 system-activemq-plan.xml 部署計(jì)劃中配置 ActiveMQContainerGBean
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://geronimo./xml/ns/deployment"
configId="org/apache/geronimo/ActiveMQServer"
parentId="org/apache/geronimo/SystemDatabase">
...
<gbean name="ActiveMQ"
class="org.activemq.gbean.ActiveMQContainerGBean">
<attribute name="brokerName">possibly-unique-broker</attribute>
<reference name="persistenceAdapter">
<gbean-name>geronimo.server:j2eeType=JMSPersistence,name=ActiveMQ.cache,*</gbean-name>
</reference>
</gbean>
<gbean name="ActiveMQ.cache"
class="org.activemq.store.cache.SimpleCachePersistenceAdapterGBean">
<attribute name="cacheSize">10000</attribute>
<reference name="longTermPersistence">
<gbean-name>geronimo.server:j2eeType=JMSPersistence,name=ActiveMQ.journal,*</gbean-name>
</reference>
</gbean>
<gbean name="ActiveMQ.jdbc"
class="org.activemq.store.jdbc.JDBCPersistenceAdapterGBean">
<reference name="dataSource">
<gbean-name>geronimo.server:J2EEApplication=null,J2EEServer=geronimo,
JCAResource=org/apache/geronimo/SystemDatabase,j2eeType=JCAManagedConnectionFactory,
name=SystemDatasource</gbean-name>
</reference>
</gbean>
<gbean name="ActiveMQ.tcp.${PlanServerHostname}.${PlanActiveMQPort}"
class="org.activemq.gbean.ActiveMQConnectorGBean">
<attribute name="url">tcp://${PlanServerHostname}:${PlanActiveMQPort}</attribute>
<reference
name="activeMQContainer">
<gbean-name>geronimo.server:j2eeType=JMSServer,name=ActiveMQ,*</gbean-name>
</reference>
</gbean>
<gbean name="ActiveMQ.vm.localhost" class="org.activemq.gbean.ActiveMQConnectorGBean">
<attribute name="url">vm://localhost</attribute>
<reference name="activeMQContainer">
<gbean-name>geronimo.server:j2eeType=JMSServer,name=ActiveMQ,*</gbean-name>
</reference>
</gbean>
|
在 清單 1 中,第一個(gè) GBean 對(duì) ActiveMQ 消息代理進(jìn)行設(shè)置。該 GBean 的屬性引用了一個(gè)永久適配器并指向第二個(gè) GBean。第二個(gè) GBean 包裝了一個(gè) ActiveMQ 內(nèi)存緩存的實(shí)例,并且它引用了 ActiveMQ 的永久組件,以便支持永久性的信息。第三個(gè) GBean 連接 JDBC 數(shù)據(jù)源,以便提供永久支持,并指向 SystemDatasource —— 一個(gè) Derby RDBMS 實(shí)例。最后兩個(gè) GBeans 設(shè)置了以下兩個(gè)傳輸,用于訪問(wèn)消息代理:
- TCP 傳輸,默認(rèn)情況下,位于本地主機(jī),端口為 61616。
- in-VM 傳輸,默認(rèn)情況下,被映射到 vm://localhost。
如果需要更改此實(shí)例的配置,可以修改這個(gè) system-activemq-plan.xml 文件,然后重新部署 org/apache/geronimo/ActiveMQServer 配置。
通過(guò) JCA 1.5 資源適配器訪問(wèn)消息代理
利用 JMS 的應(yīng)用程序組件(如 servlet、JSP 或 EJB)必須通過(guò)實(shí)現(xiàn) JMS API 的庫(kù)才能訪問(wèn)消息代理。這個(gè) API 是由 Geronimo 提供的。若要用某種方法實(shí)現(xiàn)這個(gè)可以與任何 JMS 提供者(如消息代理)一起使用的 API,那么 Geronimo 必須支持 J2EE Connector (JCA) 1.5 規(guī)范。JCA 1.5 規(guī)范詳細(xì)說(shuō)明了應(yīng)用服務(wù)器 (Geronimo) 和資源適配器 (RA) 之間所需的契約 —— 由 ActiveMQ 提供的一個(gè)驅(qū)動(dòng)程序。(請(qǐng)參閱 參考資料,閱讀關(guān)于 JCA 1.5 的文章。)Geronimo 中駐留的管理應(yīng)用程序組件只有通過(guò)此 RA 才能訪問(wèn) ActiveMQ 消息代理。這是 ActiveMQ 提供給表的另一個(gè)主要好處 —— 它含有符合 JCA 1.5 且可以與之集成的 RA 實(shí)現(xiàn)。圖 2 顯示了符合 ActiveMQ JCA 1.5 的 RA。
圖 2. 符合 ActiveMQ JCA 1.5 的 RA
在 圖 2 中,可以看到 ActiveMQ RA 通過(guò)已定義好的 JCA 1.5 系統(tǒng)契約與 Geronimo 的安全和事物處理系統(tǒng)發(fā)生的交互。ActiveMQ RA 支持出站連接(JMS 向外調(diào)用消息代理)和入站連接(用 ActiveMQ 初始的調(diào)用來(lái)調(diào)用 MDB)。對(duì)于出站連接,消息發(fā)送應(yīng)用程序可以將提供者(本例中為 ActiveMQ)注冊(cè)為分布式事物處理的一部分,也可以包括其他資源管理程序(如 RDBMS)。對(duì)于入站連接,一般先通過(guò)激活 MDB,Geronimo 才能啟動(dòng)事物處理。在目前的 JCA 1.5 規(guī)范以及 Geronimo 實(shí)現(xiàn)中,入站連接不與容器的安全子系統(tǒng)交互。
WorkManager 契約是 JCA 1.5 的一部分。它允許 RA 向應(yīng)用程序服務(wù)器提交工作,以便于執(zhí)行。這樣允許服務(wù)器 —— Geronimo —— 對(duì)符合 RA 的線程管理和工作分配進(jìn)行控制。對(duì)于 ActiveMQ,此功能用于管理入站連接的線程。有關(guān)此功能的更多信息,請(qǐng)參閱“JCA 1.5, Part 3: Message inflow”(developerWorks,2005 年 6 月)。
清單 2 顯示了 system-jms-plan.xml 部署計(jì)劃的一個(gè)片段。此計(jì)劃對(duì) RA 實(shí)例的組件進(jìn)行了配置,正如 JCA 1.5 規(guī)范中部署描述符詳細(xì)描述的那樣。就 ActiveMQ RA 而言,這些組件包括 RA 實(shí)現(xiàn)類(lèi)、出站連接工廠、主題和隊(duì)列(管理的對(duì)象)。
清單 2 中部署計(jì)劃的配置如下:
- 一個(gè) ActiveMQ RA 實(shí)例,它使用 TCP 傳輸協(xié)議來(lái)訪問(wèn) 清單 2 中所配置的 ActiveMQ 消息代理。
- 一個(gè) JCA 1.5 WorkManager 實(shí)現(xiàn),由 Geronimo 提供,用于 ActiveMQ RA 實(shí)例。
- 一個(gè) JMS 連接工廠,可用于創(chuàng)建隊(duì)列連接(通過(guò) QueueConnectionFactory 界面)或主題連接(通過(guò) TopicConnectionFactory 界面)。
- 一個(gè)管理對(duì)象,它包含一個(gè)名為 MDBTransferBeanOutQueue 的 JMS 隊(duì)列。
- 一個(gè)管理對(duì)象,它包含一個(gè)名為 SendReceiveQueue 的 JMS 隊(duì)列。
如果需要修改這個(gè) JMS RA 的默認(rèn)配置(例如,添加其他隊(duì)列),則需要在 system-jms-plan.xml 部署計(jì)劃中進(jìn)行適當(dāng)?shù)母摹R谷魏胃挠行?,首先要取消?duì) org/apache/geronimo/SystemJMS 配置的部署,然后,重新部署該配置。對(duì)于其他配置 ActiveMQ RA 實(shí)例的部署計(jì)劃,請(qǐng)參閱側(cè)欄 部署 ActiveMQ RA。
 |
部署 ActiveMQ RA
除了在 system-jms-plan.xml 中進(jìn)行服務(wù)器啟動(dòng)的部署以外,還可以使用下列方法之一部署 ActiveMQ RA 實(shí)例:
- 獨(dú)立方法,使用 ra.xml 部署計(jì)劃。
- 使用企業(yè)應(yīng)用程序 aRchive (EAR),在 geronimo-application.xm 部署計(jì)劃中的 <module> 元素內(nèi)進(jìn)行部署。
- 使用 Web 應(yīng)用程序 aRchive (WAR),在 geronimo-web.xml 部署計(jì)劃中的 <resource> 元素內(nèi)進(jìn)行部署。
|
|
應(yīng)用程序客戶機(jī) JMS 訪問(wèn)
Geronimo 客戶機(jī)應(yīng)用程序容器支持的 J2EE 應(yīng)用程序客戶機(jī)可以訪問(wèn) ActiveMQ 消息代理。圖 3 顯示了一些客戶機(jī)訪問(wèn)配置。
圖 3. J2EE 和非 J2EE 客戶機(jī)對(duì)消息代理的訪問(wèn)
圖 3 中上部的配置顯示 J2EE 客戶機(jī)應(yīng)用程序?qū)蛻魴C(jī)范圍內(nèi)部署的 RA 的訪問(wèn)情況。這個(gè) RA 實(shí)例被配置成可以訪問(wèn)服務(wù)器端的消息代理。圖 3 中的第二個(gè)配置顯示另一個(gè) J2EE 客戶機(jī),該客戶機(jī)附帶一個(gè)客戶機(jī)范圍內(nèi)部署的 RA,但是也可以訪問(wèn)在客戶機(jī)上部署的消息代理實(shí)例。(這種情況在非連續(xù)的操作中非常有用,例如,偶爾連接到企業(yè)網(wǎng)絡(luò)的筆記本電腦。)在第三個(gè)配置中,非 J2EE 客戶機(jī)可以通過(guò)任何配置的傳輸直接訪問(wèn) ActiveMQ 消息代理。該操作示例演示了如何創(chuàng)建這樣一個(gè)獨(dú)立的、非 J2EE ActiveMQ 應(yīng)用程序客戶機(jī)。
創(chuàng)建 JMS 應(yīng)用程序:servlet 生產(chǎn)者和本地 ActiveMQ 消費(fèi)者
這里的第一個(gè)示例顯示 servlet 如何通過(guò) JMS 與外部非 J2EE 應(yīng)用程序通信。該示例使用了稱(chēng)為 SendReceiveQueue 的全局服務(wù)器范圍的隊(duì)列(參見(jiàn) 清單 2)。它包括 JMS 消息發(fā)送方(生產(chǎn)者)和 JMS 消息接收方(消費(fèi)者)。生產(chǎn)者是一個(gè) servlet,稱(chēng)為 SenderServlet,它在 Geronimo 內(nèi)部運(yùn)行。調(diào)用程序是一個(gè)獨(dú)立的 ActiveMQ 客戶機(jī),不使用 Geronimo 對(duì) JMS 提供支持。圖 4 顯示了這個(gè)示例中的交互情況。
圖 4. SenderServlet 和 ActiveMQ 接收方應(yīng)用程序
在 圖 4 中,應(yīng)用程序流程如下:
- 用戶通過(guò) Web 瀏覽器訪問(wèn) SenderServlet。
- SenderServlet 由 Geronimo 承載,向用戶顯示一個(gè)數(shù)據(jù)項(xiàng)窗體。
- 用戶輸入文本消息,然后單擊 Send。
- SenderServlet 處理窗體提交的信息,并使用 JMS 將文本消息發(fā)送給 SendReceiveQueue。
- 獨(dú)立的、非 J2EE ActiveMQ 客戶機(jī)讀取 SendReceiveQueue 并顯示收到的消息。
本示例的 Web 應(yīng)用程序源代碼位于代碼下載文件夾的 war_only 目錄中(請(qǐng)參閱下面 參考資料 的下載部分)??蛻魴C(jī)代碼位于 mqclient 子目錄中。
如果只是想嘗試使用此示例,可以在 war_only/dist 子目錄中找到 sender.war 文檔,只需將下面的應(yīng)用程序文檔部署在 Geronimo 服務(wù)器上即可:
java -jar bin/deployer.jar sender.war
|
出現(xiàn)提示時(shí),請(qǐng)輸入用戶名 system 和密碼 manager 。按照 readme.txt 文件中的說(shuō)明來(lái)構(gòu)建客戶機(jī)。接下來(lái),請(qǐng)轉(zhuǎn)到 mqclient 目錄,并使用 run.bat 文件運(yùn)行客戶機(jī)應(yīng)用程序。這時(shí)將啟動(dòng)客戶機(jī),并等待傳入消息。
通過(guò)在瀏覽器地址欄輸入 http://localhost:8080/sender/sendform.cgi 可以訪問(wèn)數(shù)據(jù)項(xiàng) servlet。
將文本消息輸入到字段中,然后單擊 Send。您會(huì)注意到 ActiveMQ 客戶機(jī)會(huì)立即收到該消息并將其打印出來(lái)。
瀏覽 清單 3,可以看到一些 SendServlet.java 代碼,在 war_only/src 目錄中,可以找到完整的源代碼。
在 清單 3 中,servlet 針對(duì) HTTP GET 請(qǐng)求生成輸入窗體,并根據(jù) HTTP POST 請(qǐng)求處理窗體提交的信息。實(shí)際的 doPost() 方法用于解析輸入的消息、創(chuàng)建隊(duì)列連接、啟動(dòng)會(huì)話和將消息發(fā)送到隊(duì)列。
通過(guò) Java 命名和目錄界面 (JNDI),servlet init() 方法可以查找連接工廠和隊(duì)列。Geronimo 提供 JNDI 映射服務(wù)。您將看到隊(duì)列是使用 java:comp/env/dwSendReceiveQueue 查找的。隊(duì)列的名稱(chēng)將映射到 Web 應(yīng)用程序的 web.xml 部署描述符中。清單 4 再現(xiàn)了 web.xml 的相關(guān)片段。
清單 4. web.xml 中的 JNDI 映射和資源引用
<resource-ref>
<res-ref-name>DefaultActiveMQConnectionFactory</res-ref-name>
<res-type>javax.jms.QueueConnectionFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<message-destination-ref>
<message-destination-ref-name>dwSendReceiveQueue</message-destination-ref-name>
<message-destination-type>javax.jms.Queue</message-destination-type>
<message-destination-usage>Produces</message-destination-usage>
<message-destination-link>SendReceiveQueue</message-destination-link>
</message-destination-ref>
|
在 清單 4 中,<message-destination-ref> 通過(guò) <message-destination-link> 子元素將名稱(chēng) dwSendReceiveQueue 映射到系統(tǒng)范圍的隊(duì)列中。遺憾的是,J2EE 1.4 規(guī)范不支持 web.xml 中 <resource-ref> 元素中的 <resource-link> 子元素。因此,必須使用連接工廠的實(shí)際資源名 (DefaultActiveMQConnectionFactory),或者必須創(chuàng)建一個(gè)自定義部署計(jì)劃(如 geronimo-web.xml)以映射該引用。
對(duì) ActiveMQ 消息接收方客戶機(jī)進(jìn)行編碼
接收方是本地 ActiveMQ 客戶機(jī),它不需要任何 Geronimo 客戶機(jī)支持。它通過(guò) TCP 傳輸和 URL tcp://localhost:61616 訪問(wèn) Geronimo 中駐留的 ActiveMQ 消息代理。此客戶機(jī) JMSReceiver 的部分源代碼如 清單 5 所示。在 war_only/clientsrc 目錄中,可以看到完整的源代碼。
清單 5. JMSReceiver.java —— 非 J2EE JMS 消息接收方客戶機(jī)
package com.ibm.dw.geronimo.jms;
import javax.jms.*;
import org.activemq.ActiveMQConnectionFactory;
public class JMSReceiver {
protected Queue queue;
protected String queueName = "SendReceiveQueue";
protected String url = "tcp://localhost:61616";
protected int ackMode = Session.AUTO_ACKNOWLEDGE;
public static void main(String[] args) {
JMSReceiver msgReceiver = new JMSReceiver();
msgReceiver.run();
}
public void run() {
try {
ActiveMQConnectionFactory connectionFactory =
new ActiveMQConnectionFactory(url);
QueueConnection connection =
(QueueConnection)
connectionFactory.createConnection();
connection.start();
MessageConsumer consumer = null;
Session session = connection.createQueueSession(
false,
Session.AUTO_ACKNOWLEDGE);
queue = session.createQueue(queueName);
consumer = session.createConsumer(queue);
System.out.println("Waiting for message (max 5)");
for (int i = 0; i < 5; i++) {
Message message = consumer.receive();
processMessage(message);
}
System.out.println("Closing connection");
consumer.close();
session.close();
connection.close();
} catch (Exception e) {
...
}
}
public void processMessage(Message message) {
try {
TextMessage txtMsg = (TextMessage) message;
System.out.println("Received a message: " + txtMsg.getText());
} catch (Exception e) {
...
}
}
}
|
在 清單 5 中,JMSReceiver 完全獨(dú)立于 J2EE 代碼。無(wú)需執(zhí)行 JNDI 查找或目標(biāo)映射,因?yàn)?ActiveMQ 本地庫(kù)會(huì)自動(dòng)執(zhí)行等同的操作。
通過(guò)混合使用 JMS API 和 ActiveMQ 支持庫(kù),對(duì)這個(gè)非 J2EE 消息消費(fèi)者進(jìn)行編碼非常簡(jiǎn)單。使用 Geronimo 的支持對(duì) J2EE 消息消費(fèi)者進(jìn)行編碼也很簡(jiǎn)單。下一個(gè)示例將顯示如何構(gòu)建有用的 J2EE 消息消費(fèi)者:MDB,該程序可以將產(chǎn)品類(lèi)別添加到 Really Big Pet Store 示例中。
創(chuàng)建用于數(shù)據(jù)更新的 MDB
第二個(gè)操作示例將顯示如何構(gòu)建 MDB。這個(gè)示例使用與第一個(gè)示例完全相同的 SendServlet 代碼,但是,消息消費(fèi)者現(xiàn)在是同一企業(yè)應(yīng)用程序內(nèi)的 MDB(綁定在同一 EAR 中)。圖 5 舉例說(shuō)明了這個(gè)示例的操作過(guò)程。
圖 5. MDB 示例的操作過(guò)程
這個(gè)示例使用的代碼來(lái)自文章“Geronimo! 第 2 部分:馴服 J2EE 1.4 這匹野馬”(developerWorks,2005 年 5 月)。這篇文章還包含關(guān)于 Really Big Pet Store 操作的更多信息。
在 圖 5 中,初始 Web 應(yīng)用程序的操作過(guò)程被完好地保留下來(lái)。購(gòu)物者可以使用瀏覽器訪問(wèn)該店鋪的基于 JSP 的用戶界面。StoreController servlet 使用稱(chēng)為 CategoriesBean 的無(wú)狀態(tài)會(huì)話 EJB 的 getCats() 方法獲取產(chǎn)品類(lèi)別信息。
對(duì) CategoriesBean 進(jìn)行修改,以便使用新的 helper 類(lèi) CategoryData 來(lái)獲得類(lèi)別列表。
MDB 又稱(chēng)為 CategoriesMDB。在將消息放入 SendReceiveQueue 時(shí),EJB 會(huì)被激活。CategoriesMDB 提取此消息內(nèi)容,并通過(guò)它將產(chǎn)品類(lèi)別添加到 CategoryData 中。因?yàn)?CategoriesBean 的會(huì)話 EJB 可以使用 CategoryData 獲得每個(gè)屏幕更新,所以購(gòu)物者會(huì)立即看到新的類(lèi)別。
在生產(chǎn)環(huán)境中,代表類(lèi)別的實(shí)體 bean 可以代替 CategoryData helper 類(lèi)。在這里,有意地避免了使用實(shí)體 bean,以簡(jiǎn)化這個(gè)示例的配置和設(shè)置。
對(duì) CategoriesMDB 進(jìn)行編碼
SenderServlet 的代碼與第一個(gè)示例的版本幾乎一樣。請(qǐng)參閱 ear_ejb/src/SenderServlet.java,以獲得完整的源代碼。
CategoriesMDB 的代碼如 清單 6 所示,您可以在 ejb/CategoriesMDB.java 找到完整的源代碼。
清單 6. CategoriesMDB —— 使用 JMS 消息并添加類(lèi)別
import javax.ejb.*;
import javax.jms.*;
import com.ibm.dw.reallybigpet.ejb.CategoryData;
public class CategoriesMDB
implements MessageDrivenBean,MessageListener {
private transient MessageDrivenContext mdc = null;
public CategoriesMDB() {
}
public void setMessageDrivenContext(MessageDrivenContext mdc) {
this.mdc = mdc;
}
public void ejbCreate() {
}
public void onMessage(Message inMessage) {
TextMessage msg = null;
try {
if (inMessage instanceof TextMessage) {
msg = (TextMessage) inMessage;
CategoryData.getInstance().addCat(msg.getText());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void ejbRemove() {
}
}
|
MDB 代碼非常簡(jiǎn)單。清單 7 中突出顯示的行是執(zhí)行任務(wù)的位置。隊(duì)列收到 JMS 消息時(shí),Geronimo 將執(zhí)行以下操作:
 |
父配置和類(lèi)裝載
確保將 geronimo-application.xml 中的應(yīng)用程序元素的 parentId 屬性設(shè)為 org/apache/geronimo/SystemJMS 。這樣可以確保您正在使用 JMS RA 的類(lèi)裝載器。相反,如果將 parentId 設(shè)為 org/apache/geronimo/System ,那么您將遇到類(lèi)似 java.lang.ClassNotFoundException: org.activemq.ra.ActiveMQActivationSpec 的類(lèi)裝載問(wèn)題。這是使用 Geronimo 部署 MDB 時(shí)可能出現(xiàn)的最常見(jiàn)錯(cuò)誤。
|
|
- 獲取該消息。
- 激活這個(gè) MDB 實(shí)例。
- 調(diào)用 MDB 的
onMessage() 方法,并將收到的消息作為該方法的一個(gè)參數(shù)傳遞。
您需要在部署描述符 ejb-jar.xml 中使用關(guān)聯(lián)的 JMS 目標(biāo)(或隊(duì)列)配置 MDB。在 清單 7 中可以看到它的一個(gè)示例。
在 清單 8 中,SendReceiveQueue 通過(guò) <message-driven> 元素中的 <activation-config> 子元素與 MDB 關(guān)聯(lián),要選擇將要使用的 JMS RA,請(qǐng)創(chuàng)建與 清單 8 類(lèi)似的自定義 openejb=jar.xml。
清單 8. 自定義部署計(jì)劃 openejb-jar.xml 來(lái)選擇 JMS RA
<?xml version="1.0"?>
<openejb-jar xmlns="http://www./xml/ns/openejb-jar"
configId="catmdb"
parentId="org/apache/geronimo/SystemJMS"
>
<enterprise-beans>
<message-driven>
<ejb-name>CatMDB</ejb-name>
<resource-adapter>
<resource-link>ActiveMQ RA</resource-link>
</resource-adapter>
</message-driven>
</enterprise-beans>
</openejb-jar>
|
在 清單 8 中,默認(rèn)的系統(tǒng)范圍的 RA 使用 <resource-link> 元素按名稱(chēng)進(jìn)行選擇。請(qǐng)參閱側(cè)欄 父配置和類(lèi)裝載,以了解 geronimo-application.xml 部署計(jì)劃所需的信息。
要嘗試使用這個(gè)示例,請(qǐng)部署 reallybigpet.ear 應(yīng)用程序,它位于 ear_ejb/dist 目錄中。要訪問(wèn)該店鋪,請(qǐng)將瀏覽器指向 http://localhost:8080/ReallyBigPetStore/store.cgi。要訪問(wèn)添加類(lèi)別的窗體,請(qǐng)將瀏覽器指向 http://localhost:8080/ReallyBigPetStore/sendform.cgi。
結(jié)束語(yǔ)
ActiveMQ 為 Geronimo 提供了高質(zhì)量的 JMS 服務(wù),同時(shí),Geronimo 為 ActiveMQ 提供了基于 JDBC 的持續(xù)性、生命周期管理(通過(guò)遵從 JCA 1.5)、安全性、傳輸和工作管理。這種共存關(guān)系使 Geronimo 用戶獲得了兩者的優(yōu)點(diǎn):可以訪問(wèn)通過(guò) ActiveMQ 的豐富傳輸和客戶機(jī)支持增強(qiáng)的標(biāo)準(zhǔn)化了的 J2EE 1.4 JMS 和 MDB 工具。
致謝
作者衷心感謝 Geronimo 團(tuán)隊(duì)的 David Jencks,在本文評(píng)審期間,他給予了專(zhuān)業(yè)幫助。
參考資料
關(guān)于作者
|