内容


Geronimo 中 JMS、MDB 和 ActiveMQ 的使用技巧

了解 Geronimo 和 ActiveMQ JMS 引擎之间的共存关系

Comments

JMS API 是 J2EE 平台的整体组成部分,允许在松耦合组件之间进行基于消息的通信。通过客户机、Web 层组件、业务层企业 JavaBeans (EJB) 和企业信息系统 (EIS) 层服务之间的 J2EE 堆栈可以发送和接收消息。这些消息是异步发送的,消息发出后,发送方能够继续使用其他应用程序逻辑,消息代理 (message broker) 负责代表发送方传递消息。消息可以在特定的端点(发送方和接收方)之间发送和接收,或通过公共/订阅交互模式在生产者与消费者之间进行匿名传递。在 J2EE 架构内部,通过 JMS 进行通信的组件可以使用容器提供的安全和事物处理功能。Geronimo 通过集成名为 ActiveMQ 的开源项目来支持这个重要的 API。

本文将探讨如何在 Geronimo 中集成 ActiveMQ。您将了解 Geronimo 如何从集成中受益,以及 ActiveMQ 功能如何通过驻留在 Geronimo 内部得到增强。可以从本文下载一个操作示例,该示例揭示了如何对通过 JMS 进行通信的客户机和组件进行编码。另一个示例显示了如何在 Geronimo 内部创建万能的 MDB。

ActiveMQ:最佳的开源 JMS 实现

在 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 服务器的支持。

在 GBean 中包装 ActiveMQ 消息代理

ActiveMQ 消息代理被设计成可嵌入式的。Geronimo 充分利用了这一功能。通过提供包装已嵌入消息代理的 GBean 容器,可以创建 ActiveMQContainerGBean。ActiveMQ 消息代理的其他组件也被包装到 GBeans 中,您很快就会看到这种情形。图 1 说明了 ActiveMQContainerGBean 是如何嵌入 ActiveMQ 消息代理的。

图 1. ActiveMQContainerGBean
ActiveMQContainerGBean
ActiveMQContainerGBean

通过将 ActiveMQ 消息代理包装到 GBean 中,该代理的生命周期由 Geronimo 管理。具体地说,您可以使用 Geronimo 部署程序和管理工具部署、启动和管理 ActiveMQ 消息代理实例。消息代理的可配置属性是作为 GBean 属性公开的。在 图 1 中,ActiveMQContainerGBean 对 ActiveMQ 消息代理进行了包装,并提供了生活周期管理和配置服务。除了提供生命周期和配置支持外,Geronimo 还对持久消息提供持久支持。目前的 ActiveMQ 服务器配置使用默认 Derby RDBMS 实例来处理持久消息。

由 Geronimo 提供的默认 J2EE 服务器集集成了一个 ActiveMQ 消息代理实例。这个集合在服务器启动时启动消息代理,通常使用的命令行如下:

java -jar bin\server.jar

要查看此实例是如何配置的,可以检查 Geronimo 源代码分配的计划目录中的 system-activemq-plan.xml 部署计划。您将看到 ActiveMQContainerGBean 和其他相关的 ActiveMQ 组件是如何配置的。清单 1 显示了此部署计划中的相关字段。

清单 1. 在 system-activemq-plan.xml 部署计划中配置 ActiveMQContainerGBean
<?xml version="1.0" encoding="UTF-8"?>
<configuration
    xmlns="http://geronimo.apache.org/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 中,第一个 GBean 对 ActiveMQ 消息代理进行设置。该 GBean 的属性引用了一个永久适配器并指向第二个 GBean。第二个 GBean 包装了一个 ActiveMQ 内存缓存的实例,并且它引用了 ActiveMQ 的永久组件,以便支持永久性的信息。第三个 GBean 连接 JDBC 数据源,以便提供永久支持,并指向 SystemDatasource —— 一个 Derby RDBMS 实例。最后两个 GBeans 设置了以下两个传输,用于访问消息代理:

  • TCP 传输,默认情况下,位于本地主机,端口为 61616。
  • in-VM 传输,默认情况下,被映射到 vm://localhost。

如果需要更改此实例的配置,可以修改这个 system-activemq-plan.xml 文件,然后重新部署 org/apache/geronimo/ActiveMQServer 配置。

通过 JCA 1.5 资源适配器访问消息代理

利用 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
符合 ActiveMQ JCA 1.5 的 RA
符合 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 中部署计划的配置如下:

  • 一个 ActiveMQ RA 实例,它使用 TCP 传输协议来访问 清单 2 中所配置的 ActiveMQ 消息代理。
  • 一个 JCA 1.5 WorkManager 实现,由 Geronimo 提供,用于 ActiveMQ RA 实例。
  • 一个 JMS 连接工厂,可用于创建队列连接(通过 QueueConnectionFactory 界面)或主题连接(通过 TopicConnectionFactory 界面)。
  • 一个管理对象,它包含一个名为 MDBTransferBeanOutQueue 的 JMS 队列。
  • 一个管理对象,它包含一个名为 SendReceiveQueue 的 JMS 队列。

如果需要修改这个 JMS RA 的默认配置(例如,添加其他队列),则需要在 system-jms-plan.xml 部署计划中进行适当的更改。要使任何更改有效,首先要取消对 org/apache/geronimo/SystemJMS 配置的部署,然后,重新部署该配置。对于其他配置 ActiveMQ RA 实例的部署计划,请参阅侧栏 部署 ActiveMQ RA

应用程序客户机 JMS 访问

Geronimo 客户机应用程序容器支持的 J2EE 应用程序客户机可以访问 ActiveMQ 消息代理。图 3 显示了一些客户机访问配置。

图 3. J2EE 和非 J2EE 客户机对消息代理的访问
J2EE 和非 J2EE 客户机对消息代理的访问
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 接收方应用程序
SenderServlet 和 ActiveMQ 接收方应用程序

图 4 中,应用程序流程如下:

  1. 用户通过 Web 浏览器访问 SenderServlet。
  2. SenderServlet 由 Geronimo 承载,向用户显示一个数据项窗体。
  3. 用户输入文本消息,然后单击 Send
  4. SenderServlet 处理窗体提交的信息,并使用 JMS 将文本消息发送给 SendReceiveQueue。
  5. 独立的、非 J2EE ActiveMQ 客户机读取 SendReceiveQueue 并显示收到的消息。

本示例的 Web 应用程序源代码位于代码下载文件夹的 war_only 目录中(请参阅下面 参考资料 的下载部分)。客户机代码位于 mqclient 子目录中。

如果只是想尝试使用此示例,可以在 war_only/dist 子目录中找到 sender.war 文档,只需将下面的应用程序文档部署在 Geronimo 服务器上即可:

java -jar bin/deployer.jar sender.war

出现提示时,请输入用户名 system 和密码 manager。按照 readme.txt 文件中的说明来构建客户机。接下来,请转到 mqclient 目录,并使用 run.bat 文件运行客户机应用程序。这时将启动客户机,并等待传入消息。

通过在浏览器地址栏输入 http://localhost:8080/sender/sendform.cgi 可以访问数据项 servlet。

将文本消息输入到字段中,然后单击 Send。您会注意到 ActiveMQ 客户机会立即收到该消息并将其打印出来。

浏览 清单 3,可以看到一些 SendServlet.java 代码,在 war_only/src 目录中,可以找到完整的源代码。

清单 3 中,servlet 针对 HTTP GET 请求生成输入窗体,并根据 HTTP POST 请求处理窗体提交的信息。实际的 doPost() 方法用于解析输入的消息、创建队列连接、启动会话和将消息发送到队列。

通过 Java 命名和目录界面 (JNDI),servlet init() 方法可以查找连接工厂和队列。Geronimo 提供 JNDI 映射服务。您将看到队列是使用 java:comp/env/dwSendReceiveQueue 查找的。队列的名称将映射到 Web 应用程序的 web.xml 部署描述符中。清单 4 再现了 web.xml 的相关片段。

清单 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> 通过 <message-destination-link> 子元素将名称 dwSendReceiveQueue 映射到系统范围的队列中。遗憾的是,J2EE 1.4 规范不支持 web.xml 中 <resource-ref> 元素中的 <resource-link> 子元素。因此,必须使用连接工厂的实际资源名 (DefaultActiveMQConnectionFactory),或者必须创建一个自定义部署计划(如 geronimo-web.xml)以映射该引用。

对 ActiveMQ 消息接收方客户机进行编码

接收方是本地 ActiveMQ 客户机,它不需要任何 Geronimo 客户机支持。它通过 TCP 传输和 URL tcp://localhost:61616 访问 Geronimo 中驻留的 ActiveMQ 消息代理。此客户机 JMSReceiver 的部分源代码如 清单 5 所示。在 war_only/clientsrc 目录中,可以看到完整的源代码。

清单 5. JMSReceiver.java —— 非 J2EE JMS 消息接收方客户机
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 完全独立于 J2EE 代码。无需执行 JNDI 查找或目标映射,因为 ActiveMQ 本地库会自动执行等同的操作。

通过混合使用 JMS API 和 ActiveMQ 支持库,对这个非 J2EE 消息消费者进行编码非常简单。使用 Geronimo 的支持对 J2EE 消息消费者进行编码也很简单。下一个示例将显示如何构建有用的 J2EE 消息消费者:MDB,该程序可以将产品类别添加到 Really Big Pet Store 示例中。

创建用于数据更新的 MDB

第二个操作示例将显示如何构建 MDB。这个示例使用与第一个示例完全相同的 SendServlet 代码,但是,消息消费者现在是同一企业应用程序内的 MDB(绑定在同一 EAR 中)。图 5 举例说明了这个示例的操作过程。

图 5. MDB 示例的操作过程
MDB 示例的操作过程
MDB 示例的操作过程

这个示例使用的代码来自文章“Geronimo! 第 2 部分:驯服 J2EE 1.4 这匹野马”(developerWorks,2005 年 5 月)。这篇文章还包含关于 Really Big Pet Store 操作的更多信息。

图 5 中,初始 Web 应用程序的操作过程被完好地保留下来。购物者可以使用浏览器访问该店铺的基于 JSP 的用户界面。StoreController servlet 使用称为 CategoriesBean 的无状态会话 EJB 的 getCats() 方法获取产品类别信息。

对 CategoriesBean 进行修改,以便使用新的 helper 类 CategoryData 来获得类别列表。

MDB 又称为 CategoriesMDB。在将消息放入 SendReceiveQueue 时,EJB 会被激活。CategoriesMDB 提取此消息内容,并通过它将产品类别添加到 CategoryData 中。因为 CategoriesBean 的会话 EJB 可以使用 CategoryData 获得每个屏幕更新,所以购物者会立即看到新的类别。

在生产环境中,代表类别的实体 bean 可以代替 CategoryData helper 类。在这里,有意地避免了使用实体 bean,以简化这个示例的配置和设置。

对 CategoriesMDB 进行编码

SenderServlet 的代码与第一个示例的版本几乎一样。请参阅 ear_ejb/src/SenderServlet.java,以获得完整的源代码。

CategoriesMDB 的代码如 清单 6 所示,您可以在 ejb/CategoriesMDB.java 找到完整的源代码。

清单 6. CategoriesMDB —— 使用 JMS 消息并添加类别
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 代码非常简单。清单 7 中突出显示的行是执行任务的位置。队列收到 JMS 消息时,Geronimo 将执行以下操作:

  1. 获取该消息。
  2. 激活这个 MDB 实例。
  3. 调用 MDB 的 onMessage() 方法,并将收到的消息作为该方法的一个参数传递。

您需要在部署描述符 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
<?xml version="1.0"?>
<openejb-jar xmlns="http://www.openejb.org/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 中,默认的系统范围的 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,在本文评审期间,他给予了专业帮助。


下载资源


相关主题

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • 获得关于 ActiveMQ 项目 的详细信息。Geronimo 的 JMS 提供者是 ActiveMQ。
  • 请参阅 David Currie 撰写的优秀文章“JCA 1.5,第 3 部分: 消息输入流”(developerWorks,2005 年 6 月),以了解目前 J2EE 1.4 和 JCA 1.5 如何允许 MDB 实现任何界面。
  • 请参阅由两个部分组成的 Geronimo 系列。第 1 部分“Geronimo!第 1 部分: 支持 J2EE 1.4 引擎”是对 Geronimo 和一些概念的简要介绍,第 2 部分“Geronimo!第 2 部分: 驯服 J2EE 1.4 这匹野马 ”讲述了 Geronimo 的配置、部署和管理,并提供一些部署 Web 应用程序和 EJB 的操作示例(developerWorks,2005 年 5 月)。
  • 下载 Gluecode 标准版,它是一个基于 Apache Geronimo 的开源应用服务器。
  • 访问 Geronimo 项目 的官方网站,该网站提供了关于邮件列表和 wiki 的最新源代码、二进制文件和一个活跃社区。
  • Geronimo 使用 Apache Maven 来管理项目构建。使用 Subversion 来管理大多数项目的版本控制,有些项目仍然位于 CVS 之上。
  • 请参阅 Apache Geronimo 项目区,以获得来自 developerWorks 的免费开放源参考资料的完整清单。
  • 浏览所有的 Apache 文章 和免费 Apache 教程,可以在 developerWorks 开放源区域找到它们。
  • 请参阅 developerWorks 开源专区,以获得大量的 how-to 信息、工具和项目更新,这些将帮助您使用开源技术进行开发,以及 IBM 的产品中使用这些技术。
  • 使用 IBM 试用软件 改进您的下一个开源开发项目,可通过下载或从 DVD 中获得获得这些软件。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Java technology
ArticleID=91407
ArticleTitle=Geronimo 中 JMS、MDB 和 ActiveMQ 的使用技巧
publish-date=08082005