级别: 初级 Sing Li (westmakaha@yahoo.com), 作者 2005 年 8 月 08 日 Apache Geronimo 是具有开放架构且功能强大的开源 Java™ 2 平台企业版 (J2EE) 1.4 服务器容器,可以承载多种现有的服务器和服务。ActiveMQ 是一个经验证的最佳开源 Java 消息服务 (JMS) 引擎,该引擎还附带一个精巧多用的功能和连接选项库。二者结合使用时,会发生奇迹般的效果!Sing Li 将为您介绍这种共存关系,并提供示例代码,帮助您开始编写 JMS 应用程序并立即使用 Geronimo 创建 Message-Driven Beans (MDB)。 JMS API 是 J2EE 平台的整体组成部分,允许在松耦合组件之间进行基于消息的通信。通过客户机、Web 层组件、业务层企业 JavaBeans (EJB) 和企业信息系统 (EIS) 层服务之间的 J2EE 堆栈可以发送和接收消息。这些消息是异步发送的,消息发出后,发送方能够继续使用其他应用程序逻辑,消息代理 (message broker) 负责代表发送方传递消息。消息可以在特定的端点(发送方和接收方)之间发送和接收,或通过公共/订阅交互模式在生产者与消费者之间进行匿名传递。在 J2EE 架构内部,通过 JMS 进行通信的组件可以使用容器提供的安全和事物处理功能。Geronimo 通过集成名为 ActiveMQ 的开源项目来支持这个重要的 API。 本文将探讨如何在 Geronimo 中集成 ActiveMQ。您将了解 Geronimo 如何从集成中受益,以及 ActiveMQ 功能如何通过驻留在 Geronimo 内部得到增强。可以从本文下载一个操作示例,该示例揭示了如何对通过 JMS 进行通信的客户机和组件进行编码。另一个示例显示了如何在 Geronimo 内部创建万能的 MDB。 在 JMS 术语中,ActiveMQ 是一个成熟而又功能丰富的 JMS 服务器或消息代理。位于 Codehaus(请参阅 参考资料)中的 ActiveMQ 支持许多不同的传输(如 TCP、SSL、UDP、多点传送、内部 JVM 和 NIO)和客户机交互(如推、拉和发行/订阅)。以一定规模的现有用户为基础,ActiveMQ 服务器完全可以独立工作,而不依赖任何容器(J2EE 或其他容器),它还可以与 J2EE 服务器主机(如 Geronimo)结合使用。 当 ActiveMQ 在 Geronimo 中运行时,会对 MDB 提供支持,即使用 JMS 消息的 EJB。JMS 的异步特性允许容器随需应变地激活 MDB,代表客户机执行 J2EE 服务器内的任务。Geronimo 会从 ActiveMQ 的富客户机支持中得到很大好处。与会话或实体 EJB 不同,MDB 不是通过严格的 EJB 界面调用的。相反,客户机只需将 JMS 消息发送到目标,便可以调用 MDB 服务。这样大大简化了使用基于 EJB 服务的客户机的编码过程。事实上,Geronimo 继承了向非 J2EE 客户机提供服务的功能 —— 这些功能受到独立 ActiveMQ 服务器的支持。
ActiveMQ 消息代理被设计成可嵌入式的。Geronimo 充分利用了这一功能。通过提供包装已嵌入消息代理的 GBean 容器,可以创建 ActiveMQContainerGBean。ActiveMQ 消息代理的其他组件也被包装到 GBeans 中,您很快就会看到这种情形。图 1 说明了 ActiveMQContainerGBean 是如何嵌入 ActiveMQ 消息代理的。 图 1. ActiveMQContainerGBean 通过将 ActiveMQ 消息代理包装到 GBean 中,该代理的生命周期由 Geronimo 管理。具体地说,您可以使用 Geronimo 部署程序和管理工具部署、启动和管理 ActiveMQ 消息代理实例。消息代理的可配置属性是作为 GBean 属性公开的。在 图 1 中,ActiveMQContainerGBean 对 ActiveMQ 消息代理进行了包装,并提供了生活周期管理和配置服务。除了提供生命周期和配置支持外,Geronimo 还对持久消息提供持久支持。目前的 ActiveMQ 服务器配置使用默认 Derby RDBMS 实例来处理持久消息。 由 Geronimo 提供的默认 J2EE 服务器集集成了一个 ActiveMQ 消息代理实例。这个集合在服务器启动时启动消息代理,通常使用的命令行如下:
要查看此实例是如何配置的,可以检查 Geronimo 源代码分配的计划目录中的 system-activemq-plan.xml 部署计划。您将看到 ActiveMQContainerGBean 和其他相关的 ActiveMQ 组件是如何配置的。清单 1 显示了此部署计划中的相关字段。 清单 1. 在 system-activemq-plan.xml 部署计划中配置 ActiveMQContainerGBean
在 清单 1 中,第一个 GBean 对 ActiveMQ 消息代理进行设置。该 GBean 的属性引用了一个永久适配器并指向第二个 GBean。第二个 GBean 包装了一个 ActiveMQ 内存缓存的实例,并且它引用了 ActiveMQ 的永久组件,以便支持永久性的信息。第三个 GBean 连接 JDBC 数据源,以便提供永久支持,并指向 SystemDatasource —— 一个 Derby RDBMS 实例。最后两个 GBeans 设置了以下两个传输,用于访问消息代理:
如果需要更改此实例的配置,可以修改这个 system-activemq-plan.xml 文件,然后重新部署 org/apache/geronimo/ActiveMQServer 配置。
利用 JMS 的应用程序组件(如 servlet、JSP 或 EJB)必须通过实现 JMS API 的库才能访问消息代理。这个 API 是由 Geronimo 提供的。若要用某种方法实现这个可以与任何 JMS 提供者(如消息代理)一起使用的 API,那么 Geronimo 必须支持 J2EE Connector (JCA) 1.5 规范。JCA 1.5 规范详细说明了应用服务器 (Geronimo) 和资源适配器 (RA) 之间所需的契约 —— 由 ActiveMQ 提供的一个驱动程序。(请参阅 参考资料,阅读关于 JCA 1.5 的文章。)Geronimo 中驻留的管理应用程序组件只有通过此 RA 才能访问 ActiveMQ 消息代理。这是 ActiveMQ 提供给表的另一个主要好处 —— 它含有符合 JCA 1.5 且可以与之集成的 RA 实现。图 2 显示了符合 ActiveMQ JCA 1.5 的 RA。 图 2. 符合 ActiveMQ JCA 1.5 的 RA 在 图 2 中,可以看到 ActiveMQ RA 通过已定义好的 JCA 1.5 系统契约与 Geronimo 的安全和事物处理系统发生的交互。ActiveMQ RA 支持出站连接(JMS 向外调用消息代理)和入站连接(用 ActiveMQ 初始的调用来调用 MDB)。对于出站连接,消息发送应用程序可以将提供者(本例中为 ActiveMQ)注册为分布式事物处理的一部分,也可以包括其他资源管理程序(如 RDBMS)。对于入站连接,一般先通过激活 MDB,Geronimo 才能启动事物处理。在目前的 JCA 1.5 规范以及 Geronimo 实现中,入站连接不与容器的安全子系统交互。 WorkManager 契约是 JCA 1.5 的一部分。它允许 RA 向应用程序服务器提交工作,以便于执行。这样允许服务器 —— Geronimo —— 对符合 RA 的线程管理和工作分配进行控制。对于 ActiveMQ,此功能用于管理入站连接的线程。有关此功能的更多信息,请参阅“JCA 1.5, Part 3: Message inflow”(developerWorks,2005 年 6 月)。 清单 2 显示了 system-jms-plan.xml 部署计划的一个片段。此计划对 RA 实例的组件进行了配置,正如 JCA 1.5 规范中部署描述符详细描述的那样。就 ActiveMQ RA 而言,这些组件包括 RA 实现类、出站连接工厂、主题和队列(管理的对象)。 清单 2 中部署计划的配置如下:
如果需要修改这个 JMS RA 的默认配置(例如,添加其他队列),则需要在 system-jms-plan.xml 部署计划中进行适当的更改。要使任何更改有效,首先要取消对 org/apache/geronimo/SystemJMS 配置的部署,然后,重新部署该配置。对于其他配置 ActiveMQ RA 实例的部署计划,请参阅侧栏 部署 ActiveMQ RA。
Geronimo 客户机应用程序容器支持的 J2EE 应用程序客户机可以访问 ActiveMQ 消息代理。图 3 显示了一些客户机访问配置。 图 3. J2EE 和非 J2EE 客户机对消息代理的访问 图 3 中上部的配置显示 J2EE 客户机应用程序对客户机范围内部署的 RA 的访问情况。这个 RA 实例被配置成可以访问服务器端的消息代理。图 3 中的第二个配置显示另一个 J2EE 客户机,该客户机附带一个客户机范围内部署的 RA,但是也可以访问在客户机上部署的消息代理实例。(这种情况在非连续的操作中非常有用,例如,偶尔连接到企业网络的笔记本电脑。)在第三个配置中,非 J2EE 客户机可以通过任何配置的传输直接访问 ActiveMQ 消息代理。该操作示例演示了如何创建这样一个独立的、非 J2EE ActiveMQ 应用程序客户机。
创建 JMS 应用程序:servlet 生产者和本地 ActiveMQ 消费者 这里的第一个示例显示 servlet 如何通过 JMS 与外部非 J2EE 应用程序通信。该示例使用了称为 SendReceiveQueue 的全局服务器范围的队列(参见 清单 2)。它包括 JMS 消息发送方(生产者)和 JMS 消息接收方(消费者)。生产者是一个 servlet,称为 SenderServlet,它在 Geronimo 内部运行。调用程序是一个独立的 ActiveMQ 客户机,不使用 Geronimo 对 JMS 提供支持。图 4 显示了这个示例中的交互情况。 图 4. SenderServlet 和 ActiveMQ 接收方应用程序 在 图 4 中,应用程序流程如下:
本示例的 Web 应用程序源代码位于代码下载文件夹的 war_only 目录中(请参阅下面 参考资料 的下载部分)。客户机代码位于 mqclient 子目录中。 如果只是想尝试使用此示例,可以在 war_only/dist 子目录中找到 sender.war 文档,只需将下面的应用程序文档部署在 Geronimo 服务器上即可:
出现提示时,请输入用户名 通过在浏览器地址栏输入 http://localhost:8080/sender/sendform.cgi 可以访问数据项 servlet。 将文本消息输入到字段中,然后单击 Send。您会注意到 ActiveMQ 客户机会立即收到该消息并将其打印出来。 浏览 清单 3,可以看到一些 SendServlet.java 代码,在 war_only/src 目录中,可以找到完整的源代码。 在 清单 3 中,servlet 针对 HTTP GET 请求生成输入窗体,并根据 HTTP POST 请求处理窗体提交的信息。实际的 通过 Java 命名和目录界面 (JNDI), 清单 4. web.xml 中的 JNDI 映射和资源引用
在 清单 4 中,<message-destination-ref> 通过 <message-destination-link> 子元素将名称 dwSendReceiveQueue 映射到系统范围的队列中。遗憾的是,J2EE 1.4 规范不支持 web.xml 中 <resource-ref> 元素中的 <resource-link> 子元素。因此,必须使用连接工厂的实际资源名 (DefaultActiveMQConnectionFactory),或者必须创建一个自定义部署计划(如 geronimo-web.xml)以映射该引用。 接收方是本地 ActiveMQ 客户机,它不需要任何 Geronimo 客户机支持。它通过 TCP 传输和 URL tcp://localhost:61616 访问 Geronimo 中驻留的 ActiveMQ 消息代理。此客户机 JMSReceiver 的部分源代码如 清单 5 所示。在 war_only/clientsrc 目录中,可以看到完整的源代码。 清单 5. JMSReceiver.java —— 非 J2EE JMS 消息接收方客户机
在 清单 5 中,JMSReceiver 完全独立于 J2EE 代码。无需执行 JNDI 查找或目标映射,因为 ActiveMQ 本地库会自动执行等同的操作。 通过混合使用 JMS API 和 ActiveMQ 支持库,对这个非 J2EE 消息消费者进行编码非常简单。使用 Geronimo 的支持对 J2EE 消息消费者进行编码也很简单。下一个示例将显示如何构建有用的 J2EE 消息消费者:MDB,该程序可以将产品类别添加到 Really Big Pet Store 示例中。
第二个操作示例将显示如何构建 MDB。这个示例使用与第一个示例完全相同的 SendServlet 代码,但是,消息消费者现在是同一企业应用程序内的 MDB(绑定在同一 EAR 中)。图 5 举例说明了这个示例的操作过程。 图 5. MDB 示例的操作过程 这个示例使用的代码来自文章“Geronimo! 第 2 部分:驯服 J2EE 1.4 这匹野马”(developerWorks,2005 年 5 月)。这篇文章还包含关于 Really Big Pet Store 操作的更多信息。 在 图 5 中,初始 Web 应用程序的操作过程被完好地保留下来。购物者可以使用浏览器访问该店铺的基于 JSP 的用户界面。StoreController servlet 使用称为 CategoriesBean 的无状态会话 EJB 的 对 CategoriesBean 进行修改,以便使用新的 helper 类 MDB 又称为 CategoriesMDB。在将消息放入 SendReceiveQueue 时,EJB 会被激活。CategoriesMDB 提取此消息内容,并通过它将产品类别添加到 在生产环境中,代表类别的实体 bean 可以代替 SenderServlet 的代码与第一个示例的版本几乎一样。请参阅 ear_ejb/src/SenderServlet.java,以获得完整的源代码。 CategoriesMDB 的代码如 清单 6 所示,您可以在 ejb/CategoriesMDB.java 找到完整的源代码。 清单 6. CategoriesMDB —— 使用 JMS 消息并添加类别
MDB 代码非常简单。清单 7 中突出显示的行是执行任务的位置。队列收到 JMS 消息时,Geronimo 将执行以下操作:
您需要在部署描述符 ejb-jar.xml 中使用关联的 JMS 目标(或队列)配置 MDB。在 清单 7 中可以看到它的一个示例。 在 清单 8 中,SendReceiveQueue 通过 <message-driven> 元素中的 <activation-config> 子元素与 MDB 关联,要选择将要使用的 JMS RA,请创建与 清单 8 类似的自定义 openejb=jar.xml。 清单 8. 自定义部署计划 openejb-jar.xml 来选择 JMS RA
在 清单 8 中,默认的系统范围的 RA 使用 <resource-link> 元素按名称进行选择。请参阅侧栏 父配置和类装载,以了解 geronimo-application.xml 部署计划所需的信息。 要尝试使用这个示例,请部署 reallybigpet.ear 应用程序,它位于 ear_ejb/dist 目录中。要访问该店铺,请将浏览器指向 http://localhost:8080/ReallyBigPetStore/store.cgi。要访问添加类别的窗体,请将浏览器指向 http://localhost:8080/ReallyBigPetStore/sendform.cgi。
ActiveMQ 为 Geronimo 提供了高质量的 JMS 服务,同时,Geronimo 为 ActiveMQ 提供了基于 JDBC 的持续性、生命周期管理(通过遵从 JCA 1.5)、安全性、传输和工作管理。这种共存关系使 Geronimo 用户获得了两者的优点:可以访问通过 ActiveMQ 的丰富传输和客户机支持增强的标准化了的 J2EE 1.4 JMS 和 MDB 工具。
作者衷心感谢 Geronimo 团队的 David Jencks,在本文评审期间,他给予了专业帮助。
|
联系客服