IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere | Open source | Java technology  >

利用 WAS CE v2.1 创建基于 JMS 的应用

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

戴 宣 (daixuan@cn.ibm.com), IBM 软件工程师, IBM
王 磊 (wanglsh@cn.ibm.com), IBM 软件工程师, IBM

2009 年 4 月 27 日

Java Message Service(JMS)旨在统一各种 MOM 系统接口的规范。WAS CE 是基于开源 Java EE 应用服务器 Geronimo 的产品。WAS CE 支持 EJB 及 Web 服务,同时还支持 Java EE 的消息中间件接口规范--JMS。本文将对在 WAS CE 中,开发基于 JMS 的 Java EE 应用进行介绍。

上一篇文章中,作者以一个示例介绍了在 WAS CE v2.1 中开发 Java EE 应用的流程,内容涵盖了 Java EE 5 的很多新特性,包括:Java Server Faces (JSF)、Java Persistence API (JPA)、Enterprise Java Bean (EJB) 以及 JAX-WS 2.0 。作为本系列的第二篇文章,本文将介绍 Java EE 5 的另一种技术--JMS(Java Message Service)。

文章《在 WAS CE v2.1 上开发 Java EE 应用》向您讲述了如何使用 Java Annotation、JSF、JPA、EJB 3.0 等技术在 WebSphere Application Server Communiy Edition v2.1 上开发一个 Java EE 应用。本文做为后续文章,将继续向您介绍如何使用 JMS 开发应用程序示例的后续部分。

JMS 简介

什么是 JMS

JMS 也是 Java EE 5 规范的一部分,主要用于对应用程序的消息传递及管理。目前 JMS 规范的最新版本为 1.1,规范定义了一组 API, JMS 的实现则留由不同厂商提供。JMS 的实现被称为 JMS Provider。

JMS 是一种面向消息的中间件(Message Oriented Middleware,MOM)。与 CORBA、DCOM、RMI 等通信方式相比,JMS 具有很多新特点:

  1. 消息的发送和接收是异步的,发送者无需等待。
  2. 可以一对多通信:对于一个消息可以有多个接收者。
  3. 消息发送者和接收者的生命周期无需相同:发送消息的时,接收者不一定运行;接收消息的时,发送者也不一定运行。

虽然其他通信方式也会具有 JMS 中的特点,但是 JMS 将三种特点集于一身,无疑为应用程序的开发带来了巨大的灵活性。因为 JMS 的良好特性,出现了各种 JMS Provider。其中,既有开源社区的实现,如 ActiveMQ、OpenMQ,也有商业实现,如 Websphere MQ。

JMS 的消息模型

JMS 的巨大灵活性与其消息模型有密切关系。JMS 中有两种消息模型:发布/订阅消息模型及点对点消息模型。

1. 发布/订阅消息模型

在发布/订阅模型中,消息的发送者与接收者通过主题 (Topic) 来进行通信。发送者在给定的 Topic 下发布消息;接收者订阅该 Topic 后,即可接收 Topic 下所发布的消息。发布/订阅模型的特点是:一个发布者可以将消息发送给多个接收者,甚至可以有多个发布者使用同一个 Topic 发布消息;所有订阅了 Topic 的接收者都可以接收到消息。

根据发布/订阅消息模型的特点,可以在“一对多”的情形下,使用该消息模型。即当有一个发布者需要向多个接收者发送消息时,可以使用发布/订阅消息模型。这种场景与 RSS 的消息订阅十分相似,若干接收者订阅同一个“Feed”;该“Feed”下的任一消息都会被所有订阅者接收。

2. 点对点消息模型

与发布/订阅模型相比,点对点的消息模型较为简单。消息发送者与接收者使用同一个消息队列 (Queue),发送者将消息发送至消息队列中,接收者直接去队列中取出消息。点对点消息模型的特点是:消息队列中的消息,只能被一个接收者取走;如果没有接收者接收消息,消息会继续存放在消息队列中。

根据点对点消息模型的特点,可以在“一对一”的情形下,使用该消息模型。即当有一个发送者需要一个特定接收者发送消息时,可以使用点对点消息模型。这种场景类似于发送者向接收者发送了一封“邮件”,只有实现指定的接收者,才能在自己的“邮箱”里看见“邮件”。





回页首


WAS CE 中的 JMS Provider

前一篇文章简要介绍了通过一种 Java EE 5 认证的应用服务器-WAS CE (Websphere Application Server Community Edition)。WAS CE 以 ActiveMQ 作为自身的 JMS Provider。通过 ActiveMQ 可以方便的开发 JMS 的应用。ActiveMQ 是 Apache 社区的开源项目,具有以下特性:

  1. 自带符合 JCA(Java Connector Architecture)1.5 规范的 Resource Adapter,可以使用在多种应用服务器上,如 Apache Geronimo, Redhat JBoss, GlassFish 及 Oracle WebLogic。
  2. 使用 JDBC 支持消息的快速持久化。
  3. 可以用于 Cluster、C/S 构架及 P2P(Peer-to-Peer) 的消息传递。
  4. 可以作为独立的 JMS 平台(无需应用服务器),适合单元测试。

作为 Apache 社区的顶级项目,ActiveMQ 还在不断发展。其良好的特性也为 WAS CE 增色不少。本文余下部分,将扩展前一篇文章中的示例,以阐释在 WAS CE 2.1 中 JMS 应用的开发流程。





回页首


示例

示例简介

在前一篇文章的示例中,作者假设了一个商店,应用程序只实现了用户登录和购买商品的功能。本文继续扩展这个示例,假设用户购买商品之后,商店还需要进行以下工作:

  1. 通知会计 (Accountant) 更新账目并且告知库房 (Storage) 准备出货
  2. 库房取货后通知运输队 (Transporter) 送货

显然,上述工作需要传递多个消息,如图 1 所示。


图 1. 示例流程图

示例中所需要的消息传递功能,可以使用 JMS 完成。

创建 JMS 资源

从图 1 可以看出,用户购买商品后,会计和库房都需要得到消息。这是一个消息发送者对应两个消息接收者的场景。根据 JMS 消息模型特性,这是一个“一对多”的消息发送方式,此处可以考虑使用发布/订阅模型。为此,需要定义一个 Topic,命名为 OrderTopic。然而,库房对运输队的通知则是明显的一对一消息发送,所以可以使用点对点消息发送模型。因此,需要定义一个 Queue,命名为 OrderQueue。

与前文定义一个数据源相似,JMS 也可以通过两种方式定义 JMS 资源:通过管理控制台创建和通过资源描述文件创建。在这里我们使用第二种方式,所以需要在 ShopEAR 中的增加文件:jms-resources.xml。jms-resources.xml 中定义 JMS 资源的片段见清单 1


清单 1. jms-resources.xml
<resourceadapter>
        <resourceadapter-instance>
            <resourceadapter-name>jms-resources</resourceadapter-name>
            <nam:workmanager xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2">
               <nam:gbean-link>DefaultWorkManager</nam:gbean-link>
            </nam:workmanager>
        </resourceadapter-instance>
      ......
     <adminobject>
        <adminobject-interface>javax.jms.Queue</adminobject-interface>
        <adminobject-class>
            org.apache.activemq.command.ActiveMQQueue
        </adminobject-class>
        <adminobject-instance>
            <message-destination-name>OrderQueue</message-destination-name>
            <config-property-setting name="PhysicalName">
               OrderQueue
            </config-property-setting>
        </adminobject-instance>
    </adminobject>
    <adminobject>
        <adminobject-interface>javax.jms.Topic</adminobject-interface>
        <adminobject-class>
                org.apache.activemq.command.ActiveMQTopic
       </adminobject-class>
       <adminobject-instance>
            <message-destination-name>OrderTopic</message-destination-name>
            <config-property-setting name="PhysicalName">
                 OrderTopic
            </config-property-setting>
        </adminobject-instance>
     </adminobject>

上述代码定义了一个 JMS 资源适配器 (Resource Adapter) 的实例,名称为 jms-resources。此处,可以将其理解为一个 JMS 资源组 (group)。其中,包含了三个 JMS 资源,分别为 OrderQueue、OrderTopic 及 OrderConnectionFactory。

定义上述资源时,文件中引用了一些 ActiveMQ 的类。因此,还需要在 ShopEAR 的部署文件中,添加对 ActiveMQ 资源适配器 (Resource Adapter) 的依赖。同时,将位于 WASCE_HOME/repository/org/apache/geronimo/modules/geronimo-activemq-ra/2.1.3 的 geronimo-activemq-ra-2.1.3.rar 复制到 ShopEAR 中。

在 application.xml 中添加以下代码:


清单 2. application.xml
<module>
    <connector>geronimo-activemq-ra-2.1.3.rar</connector>
</module>

在 geronimo-application.xml 中添加以下代码:


清单 3. geronimo-application.xml
<module>
    <connector>geronimo-activemq-ra-2.1.3.rar</connector>
    <alt-dd>jms-resources.xml</alt-dd>
 </module>

经过上述配置之后,就可以在代码中使用已定义的 JMS 资源。

发布/订阅消息

发布消息

为了在用户触发“购买”动作后,向会计及库房传递消息,需要在 ShopWEB 中增加一个 OrderSenderBean。同时,需要对原有 goods.jsp 进行修改,增加链接,用于触发“购买”动作。


图 2. 添加链接后的 goods.jsp 页面内容

因为 OrderSenderBean 中引用了 JMS 资源,所以还需要在 ShopWEB 的部署文件中,添加对 JMS 资源引用。

在 web.xml 中添加清单 5 所示代码。


清单 5. web.xml
<resource-ref>
    <res-ref-name>OrderConnectionFactory</res-ref-name>
    <res-type>javax.jms.TopicConnectionFactory</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<message-destination-ref>
    <message-destination-ref-name>OrderTopic</message-destination-ref-name>
    <message-destination-type>javax.jms.Topic</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
    <message-destination-link>OrderTopic</message-destination-link>
</message-destination-ref>

从代码中可以看出,此处引用的 JMS 资源正是在 jms-resources.xml 中定义的 OrderConnectionFactory 与 OrderTopic。当应用程序部署至 WAS CE 2.1 后,就可以使用这些 JMS 资源。

在 OrderSenderBean 中,有如下代码片段:


清单 6. OrderSenderBean.java
public class OrderSenderBean {
    @Resource(name = "OrderConnectionFactory")
    private ConnectionFactory factory;
    @Resource(name = "OrderTopic")
    private Topic orderTopic;
    public String orderGoods() {
     ......
    // sending message to accountant and storage
    Connection connection;
    try {
    connection = factory.createConnection();
    Session sess = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
    TextMessage msg = sess.createTextMessage("<CustomerId=" + 
    customerId + "GoodsId=" + goodsId+">");
    MessageProducer messageProducer = sess.createProducer(orderTopic);
    messageProducer.send(msg);
    System.out.println("OrderSenderBean: Order request sent to accountant and storage");
     } catch (JMSException e) {
     System.out.println("Error " + e);
     e.printStackTrace();
     }
     return "ok";
     }

OrderSenderBean 使用了 @Resource 来绑定 JMS 资源。此段代码也展示了利用 JMS 队列发送消息的流程。

创建 MDB(Message Driven Bean)

Java EE 中的 MDB 可以用于接收 JMS 消息。为此,创建两个 MDB-ShopAccountant 与 ShopStorage,分别表示会计与仓库。参见清单 7 和清单 8


清单 7. ShopAccountant 代码片段
@MessageDriven(activationConfig = {
   @ActivationConfigProperty(propertyName = "destinationType",
    propertyValue =  "javax.jms.Topic"),
   @ActivationConfigProperty(propertyName = "destination", 
    propertyValue = "OrderTopic")})
   public class ShopAccountant implements MessageListener { 	
     public void onMessage(Message message) {
     TextMessage textMessage = (TextMessage) message;
     try {
       System.out.println("ShopAccountant: Order Received \n" + 
       textMessage.getText());
       //do accountant work
        ......
        } catch (JMSException e) {
        e.printStackTrace();
        }
      }
    }


清单 8. ShopStorage 代码片段
@MessageDriven(activationConfig = {
      @ActivationConfigProperty(propertyName = "destinationType",
       propertyValue = "javax.jms.Topic"),
      @ActivationConfigProperty(propertyName = "destination", 
      propertyValue = "OrderTopic")
        })
public class ShopStorage implements MessageListener {
      public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
           System.out.println("ShopStorage:  Order Received \n" + textMessage.getText());
           //find good in storage
           ......
           } catch (JMSException e) {
              e.printStackTrace();
           }
        }
}

从代码中可见,MDB 继承了 java.jms.MessageListeneron 接口,并在 onMessage() 方法中接收并处理消息。当有消息到达时,MDB 的 onMessage() 方法会被自动执行,参数 message 就是所接收到的消息。通过 @MessageDriven 及 @ActivationConfigProperty 对 JMS 资源引用,指定了该 MDB 可以接收的消息来源。ShopAccountant 与 ShopStorage 都只接收 OrderTopic 中传递的消息。

点对点消息

发送消息

示例中,仓库完成提货后需要通知运输部门。因此,需要在 ShopStorage 中添加相应代码,以完成发送消息的动作。

以下是 ShopStorage 中添加的代码:


清单 9. ShopStorage.java
public class ShopStorage implements MessageListener {
         @Resource(name = "OrderConnectionFactory")
         private ConnectionFactory factory;
         @Resource(name = "OrderQueue")
         private Queue orderQueue;
         public void onMessage(Message message) {
           TextMessage textMessage = (TextMessage) message;
           try {
              ......
              Connection connection;
              connection = factory.createConnection();
              Session sess = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
              TextMessage msg = sess.createTextMessage();
              msg.setStringProperty("CustomerId", customerId);
              msg.setStringProperty("GoodsId", goodsId);
              MessageProducer messageProducer = sess.createProducer(orderQueue);
              messageProducer.send(msg);
              System.out.println("ShopStorage: get ready to deliver goods.");
              } catch (JMSException e) {
                   e.printStackTrace();
              }
         }
}

上述代码与 OrderSenderBean 中发送消息的代码十分相似。不同点在于这里使用了 JMS 的消息队列 (Queue) 资源 -OrderQueue,而 OrderSenderBean 则使用了 JMS 的主题 (Topic) 资源。

接收消息

创建 ShopTransporter 类表示运输部门。与之前接收消息的方式相似,ShopTransporter 也是一个消息驱动组件 (MDB)。可见,MDB 可以方便的使用于接收任何一种 JMS 消息模型。


清单 10. ShopTransporter 的代码
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = 
    "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = 
    "destination", propertyValue = "OrderQueue"),})
public class ShopTransporter implements MessageListener {
        public void onMessage(Message message) {
                   ......
        }
}


此段代码与之前的 MDB 非常相似,同样使用了 @ActivationConfigProperty 与 @MessageDriven 来绑定 JMS 资源。不同点在于,ShopTransporter 使用了消息队列 (Queue) 而不再是主题 (Topic), 表示 ShopTransporter 直接收 OrderQueue 中传递的消息。

运行

与前一篇文章相同,运行应用程序前,需要将 ShopEAR 部署至应用服务器上。登录后,用户可以点击“buy”链接,购买商品。上述代码中的输出信息将显示在应用服务器的终端中。

应用程序的输出信息如图 3 所示:


图 3. 运行结果





回页首


总结

本文以 WAS CE v2.1 为平台,通过一个示例向您阐述了 JMS 应用的基本开发过程,包括 JMS 资源及 Resouces Adapter 的创建、两类 JMS 消息 ( 通过 Queue 及 Topic) 的发送、JMS 消息的接收。无论采用何种消息模型,利用 WAS CE 2.1 开发 JMS 应用的基本流程可以归纳如下:

定义 JMS 资源

  • 创建 JMS 资源定义文件,定义所需要的 JMS 资源
  • 加入 ActiveMQ 资源适配器,作为应用程序的一个模块

发送消息

  • 利用 ConnectionFactory 创建 Connection,连接至 JMS Provider
  • 利用 Connection 创建 Session
  • 利用 Session 创建发送者及消息
  • 发送者发送消息

接收消息

  • 创建 MDB,实现 java.jms.MessageListener 接口
  • 实现 onMessage() 方法,接收并处理消息

WAS CE v2.1 为各种 Java EE 技术提供了强大的支持。通过 ActiveMQ 作为 JMS Provider,开发人员可以在 WAS CE 上便捷地开发出各种复杂应用。






回页首


下载

描述名字大小下载方法
本文代码示例OlliShop_with_jms.zip1.53 MBHTTP
关于下载方法的信息


参考资料

学习
  • 在 WAS CE v2.1 上开发 Java EE 应用:本文通过用 WAS CE v2.1 开发一个完整的应用向您展示了 Java EE 5 中的新技术,以及这些新技术在 WAS CE v2.1 上的部署和运行。

  • 访问 WAS CE V2.1 文档,了解更多关于 WAS CE 的信息。

  • 获得关于 ActiveMQ 项目 的详细信息。Geronimo 的 JMS 提供者是 ActiveMQ。WAS CE 是基于 Geronimo 的应用服务器。

  • 访问 WAS CE 项目 的论坛,获得帮助。

  • 访问 Geronimo 项目 的官方网站,该网站提供了关于邮件列表和 wiki 的最新源代码、二进制文件和一个活跃社区。

  • 查看文章 Magic with JMS,MDBs,and ActiveMQ in Geronimo,了解 Geronimo 中 JMS Provider 的构架。

  • WebSphere Application Server Community Edition V2.1 中的新增功能:本文主要讲述了 WebSphere Application Server Community Edition V2.1 中的新增功能,包括使用 Gshell 执行 Geronimo 命令、在您自己的服务器集基础上创建多个服务器组装,以及通过专家模式和新的 Monitoring Portlet 完全控制服务器的能力。

  • 从 Apache Tomcat Version 6.0 迁移到 WAS CE V2.1 :本文将逐步地指导您将一个应用程序部署到 Tomcat 6.0,然后迁移代码并将其部署到 WebSphere Application Server Community Edition V2.1。并通过该示例应用程序突出说明了这两种实现之间的一些显著差异。

  • 使用 WAS CE 开发 JPA 应用程序:本教程将向您介绍如何用 JPA 开发 WAS CE 目标平台下的 Java EE 5 应用。本教程通过一个示例应用程序的开发过程,将带您了解如何创建 JPA 项目和持久生成类,如何配置持久单元以及如何部署和运行 Web 应用程序。

  • Geronimo 专题:为您提供了 Apache Geronimo 相关的技术文章、教程、下载等资源。

  • WAS CE 产品专题:为您提供了开源应用服务器 WAS CE 相关的技术文章、教程、下载等资源。

  • Open source 专区:为您提供了开源应用服务器 WAS CE 相关的技术文章、教程、下载等资源。


获得产品和技术


作者简介

戴宣,毕业于东南大学,获得计算机科学硕士学位。IBM 软件工程师,热衷计算机网络技术、Eclipse 插件开发及 Java EE 相关技术。现为IBM 中国软件开发中心 WAS CE 开发团队成员。


王磊,毕业于上海交通大学,获得计算机科学硕士学位。IBM 中国软件开发中心 WAS CE 开发团队成员,参与了 WAS CE 应用服务器多个版本的开发工作,拥有丰富的 Java EE 经验。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款