站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > J2EE Tutorial 中文版

第7章 一个消息驱动Bean的例子 - J2EE Tutorial 中文版


第7章一个消息驱动Bean的例子

Dale Green,Kim Haase著

Iceshape Zeng译

因为消息驱动Bean建立在Java消息服务(Java Message Service,JMS)技术的基础上,所以在学习本章之前,你应该已经熟悉了如消息和消息服务等的JMS概念。你可以通过Java Message Tutorial来学习JMS,在以下网址可以找到这本书:

http://java.sun.com/products/jms/tutorial/index.html

本章讨论一个消息驱动Bean的例子,如果你没有读过第3章的什么是消息驱动Bean一节,那么再回头看一下这些基础概念。

本章内容:

例子应用程序介绍

J2EE应用程序客户端

消息驱动Bean类

onMessage方法

ejbCreate和ejbRemove方法

运行该例子

启动J2EE服务器

创建消息队列

部署该应用程序

运行客户端

用deploytool部署消息驱动Bean

指定Bean类型和事务处理机制

配置消息驱动Bean的特有属性

用deploytool配置JMS客户端

配置资源引用

配置资源环境引用

设置JNDI名

一.例子应用程序介绍

这各应用程序有两个组成部分(消息驱动Bean没有本地和远程接口):

☆ SimpleMessageClient:向消息队列发送消息的J2EE应用程序客户端

☆ SimpleMessageEJB:异步接收并处理消息队列中消息的消息驱动Bean

图7-1显示了这各应用程序的结构。客户端发送消息到消息队列,该消息队列是用j2eeadmin命令创建的。JMS服务提供者(这里是J2EE服务器)将消息传送给消息驱动Bean实例处理。

图 7-1 SimpleMessageApp结构

这个程序的源文件放在j2eetutorial/examples/src/ejb/simplemessage目录下,要编译这些源文件在j2eetutorial/examples目录下执行antsimplemessage命令。SimpleMessageApp样本文件放在j2eetutorial/examples/ears目录下。

二.J2EE应用程序客户端

SimpleMessageClient客户端程序发送消息到SimpleMessageBean监听的消息队列。首先它找到连接工厂和消息队列:

queueConnectionFactory = (QueueConnectionFactory)jndiContext.lookup("java:comp/env/jms/MyQueueConnectionFactory");

queue = (Queue)jndiContext.lookup("java:comp/env/jms/QueueName");

然后创建到消息队列的连接、消息会话和消息发送器:

queueConnection =

queueConnectionFactory.createQueueConnection();

queueSession =

queueConnection.createQueueSession(false,

Session.AUTO_ACKNOWLEDGE);

queueSender = queueSession.createSender(queue);

最后发送几条消息到消息队列:

message = queueSession.createTextMessage();

for (int i = 0; i < NUM_MSGS; i++) {

message.setText("This is message " + (i + 1));

System.out.println("Sending message: " +

message.getText());

queueSender.send(message);

}

三.消息驱动Bean类

参照SimpleMessageEJB类我们先看一下消息驱动Bean类的要求:

☆ 实现MessageDrivenBean和MessageListener接口

☆ 定义为公有(public)类

☆ 不能定义成abstract和final类

☆ 实现onMessage方法

☆ 实现ejbCreate和ejbRemove方法

☆ 必须有一个无参构造函数

☆ 不能定义finalize方法

和会话Bean和实体Bean不同,消息驱动Bean没有本地接口和远程接口。客户端不必查找消息驱动Bean的实例,并在这些接口上调用方法。虽然消息驱动Bean也没有商业方法,但是它可以有辅助类并在onMessage方法例调用这些辅助类的方法。

OnMessage方法

当消息队列收到一条消息,EJB容器调用消息驱动Bean的onMessage方法。在SimpleMessageBean类中,onMessage方法将接收到的消息恢复造型为TextMessage消息并显示消息内容:

public void onMessage(Message inMessage) {

    TextMessage msg = null;

   try {

        if (inMessage instanceof TextMessage) {

            msg = (TextMessage) inMessage;

            System.out.println

                ("MESSAGE BEAN: Message received: "

                + msg.getText());

        } else {

            System.out.println

                ("Message of wrong type: "

                + inMessage.getClass().getName());

        }

    } catch (JMSException e) {

        e.printStackTrace();

        mdc.setRollbackOnly();

    } catch (Throwable te) {

        te.printStackTrace();

    }

}

ejbCreate和ejbRemove方法

这两个方法签名的规则:

☆ 必须是公有(public)方法

☆ 返回类型是void

☆ 不能是abstract和final方法

☆ 不能有throws子句

☆ 没有参数

本例SimpleMessageBean类中ejbCreate和ejbRemove方法都是空方法。

四.运行本例子

启动J2EE服务器

在命令模式下执行如下命令:

j2ee –verbose

创建消息队列

1.创建:

2eeadmin -addJmsDestination jms/MyQueue queue

2.确认消息队列已经创建:

j2eeadmin -listJmsDestination

部署该程序

1.在deploytool工具中打开SimleMessageApp.ear文件

2.部署。注意确认在Introduction对话框中选中Return Client JAR复选框

运行客户端

1.在命令模式下进入j2eetutorial/examples/ears目录

2.设置环境变量APPCPATH为SimpleMessageAppClient.jar所在目录

3.运行客户端:

runclient -client SimpleMessageApp.ear -name SimpleMessageClient -textauth

4.在登陆提示符后输入用户名:j2ee,密码:j2ee

5.客户端显示结果:

Sending message: This is message 1

Sending message: This is message 2

Sending message: This is message 3

6.J2EE服务器终端(启动J2EE服务器的命令窗口)输出的信息:

MESSAGE BEAN: Message received: This is message 1

MESSAGE BEAN: Message received: This is message 2

MESSAGE BEAN: Message received: This is message 3

五.用deploytool部署消息驱动Bean

本章介绍部署消息驱动Bean和第2章部署企业Bean基础步骤的不同。

指定Bean类型和事务管理机制

打开新建企业Bean向导,创建消息驱动Bean(类文件加入都一样)

1.在General对话框中,选中Message-Dirven单选按钮

2.在Transaction Management对话框指定事务管理机制。可以是容器管理(Container-Managed)和Bean管理(Bean-Managed)中的任意一个。不过选择Bean管理的事务时,在第4不中就要指定应答(Acknowledgement)类型。

设置消息驱动Bean的特有属性

你可以在两个地方设置这些属性:

1.上面提到的新建企业Bean向导的第4步

2.消息驱动Bean的Message选项页(如图7-2)

需要设置的属性如下:

1.Desination Type通过两个单选按钮Queue(消息队列)和Topic(消息主题)来设置。消息队列使用点对点消息域,它只能有一个消息消费者。消息主题使用发布-订阅消息域,它可以有0个或多个消息消费者。

2.在Destination下拉框中选择你用j2eeadmin命令创建的消息的JNDI名。目的地(destination)可以是Queue和Topic中的任意类型,它是消息转发服务的提供者(it represents the source of incoming messages and the target of outgoing messages)

3.Connection Factory下拉框,在QueueConnectionFactory和TopicConnectionFactory中选择合适的一个(其实这两个工厂在选择Desination Type就被过滤了一个了)。它们提供J2EE组件访问消息服务的连接。

4.如果你设置的是Bean管理的事务,那么你也要选择应答(Acknowledgment)类型:Auto-Acknowledge或者Duplicates-OK。Auto-Acknowledge指示会话自动应答消息驱动Bean消费了消息。Duplicates-OK指示会话不必确保对发送消息的应答(The Duplicates-OK type instructs the session to lazily acknowledge the delivery of messages),它可能引起消息重复,但是降低了会话费用。

5.在JMS Message Selector域中,你可定义过滤收到消息的语句。

图 7-2 SimpleMessageEJB的Message页

六.用deploytool配置JMS客户端

本节只是简要介绍JMS客户端的配置,要知道更多信息请参考Java Message Service Tutorail。

配置资源引用

1.在树视图中选中客户端节点

2.选择Resource Refs选项页

3.点击Add按钮

4.在Coded Name列输入和客户端调用lookup方法时用的参数对应的名字(当然你也可以在这里先设置了之后,再写客户端的lookup调用)。如本例客户端lookup方法调用的参数是java:comp/env/jms/MyQueueConnectionFactory,则Coded Name应该是:jms/QueueConnectionFactory

5.在Type列选择和消息目的地(destination)类型一致的连接工厂类

6.在Authentication列,大部分时候你应该选择Container。如果在程序中编码登录消息服务,你可以选择Application。

7.在Sharable列中,确信复选框被选中。这样可以让容器优化连接。

8.在User Name和Password域输入用户名和密码。J2EE SDK的验证服务将在客户端运行时提示你输入用户名和密码。

配置资源环境引用

1.选择Resource Env. Refs选项页

2.点击Add按钮

3.在Coded Name列输入和调用lookup方法定位消息队列或者消息主题时的参数一致的名字。本例中lookup方法调用的参数为:java:comp/env/jms/QueueName,对应的Coded Name为:jms/QueueName

4.在Type列选择和目的地类型一致的类型(一般工具会自动选择一个正确的类型)

设置JNDI名

1.在树视图中选择应用程序节点

2.选择JNDI Name选项页,设置用到资源的正确JNDI名。表7-1列出了本例中使用的JNDI:

表7-1 SimpleMessageApp中的JNDI名

组件或引用名

JNDI名

SimpleMessageEJB

jms/MyQueue

jms/MyQueueConnectionFactory

jms/QueueConnectionFactory

jms/QueueName

Jms/MyQueue