译者前言
有关本章中相应源代码的下载,请参看一个Session Bean的示例。
正文
因为message-driven bean是基于Java消息服务(JMS)技术的,要理解以下示例,你必须已经熟悉基本的JMS概念,例如队列和消息。学习有关这些概念的最好的地方是Java消息服务指南:
http://java.sun.com/products/jms/tutorial/index.html
这一章讲述了一个message-driven bean示例的源代码。在开始学习前,你必须首先阅读Message-Driven Bean是什么中的基本概念。
示例应用程序概览
这个应用程序包括下列组件:
1、SimpleMessageClient:一个发送几个消息到一个队列中的J2EE应用程序客户端。
2、SimpleMessageEJB:一个异步接收和处理发送到队列中的消息的message-driven bean。
图7-1说明了这个应用程序的结构。应用程序客户端发送消息到队列中,这个队列是用j2eeadmin命令创建的。JMS供应者(在这里也就是J2EE服务器)将消息递交给一个message-driven bean的实例,这个实例将处理这个消息。
图7-1 SimpleMessageApp应用程序
在j2eetutorial/examples/src/ejb/simplemessage目录下有这个应用程序的源代码。要编译这个代码,到j2eetutorial/examples目录下。输入ant simplemessage。在j2eetutorial/examples/ears目录下有SimpleMessageApp.ear文件的示例。
J2EE应用程序客户端
SimpleMessageClient发送消息到队列中,SimpleMessageBean将对这个队列进行监听。客户端首先将定位连接factory和队列:
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);
}
Message-Driven Bean类
SimpleMessageEJB类的代码阐明了一个message-driven bean类所需满足的基本条件:
1、它实现了MessageDrivenBean接口和MessageListener接口。
2、类被定义为public。
3、类不能定义为abstract或final。
4、它实现了一个onMessage方法。
5、它实现了一个ejbCreate方法和一个ejbRemove方法。
6、它包含了一个公用的无参数的构造函数。
7、它不能定义finalize方法。
与session bean或entity bean不同,message-driven bean不具有定义客户端访问的remote接口或local接口。客户端组件不能定位message-driven bean并调用其中的方法。尽管message-driven bean不包含商业方法,但是它可能包含由onMessage方法调用的辅助方法。
onMessage方法
当队列接受到一个消息时,EJB容器调用message-driven 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方法
这些方法必须满足以下条件:
1、访问控制修饰必须是public。
2、返回类型必须是void。
3、修饰不能是static或final。
4、throws子句不能定义任何应用程序例外。
5、这个方法没有参数。
在SimpleMessageBean类中,ejbCreate方法和ejbRemove方法为空。
运行SimpleMessageEJB示例
启动J2EE服务
要显示message-driven bean的输出,你必须使用verbose模式启动服务:
j2ee -verbose
创建队列
1、使用j2eeadmin命令创建队列:
j2eeadmin -addJmsDestination jms/MyQueue queue
2、检查队列是否已被建立:
j2eeadmin -listJmsDestination
部署应用程序
1、在deploytool中打开j2eetutorial/examples/ears/SimpleMessageApp.ear文件(FileOpen)。
2、部署SimpleMessageApp应用程序(ToolsDeploy)。在Introduction对话框中,检查是否选中Return Client JAR检验栏。详细信息请参看部署J2EE应用程序.
运行客户端
1、在一个终端窗口时,到j2eetutorial/examples/ears目录下。
2、设置APPCPATH环境变量为SimpleMessageAppClient.jar。
3、在一行中输入以下命令:
runclient -client SimpleMessageApp.ear -name
SimpleMessageClient -textauth
4、在提示登录时,输入j2ee作为用户名和口令。
5、客户端会显示以下内容:
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
6、在你启动J2EE服务(用verbose模式)的终端窗口下,会显示以下内容:
MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3
Message-Driven Bean的Deploytool提示
第二章概括了创建和封装enterprise bean的基本步骤。这一章我们将介绍对于message-driven bean在deploytool中必须执行的任务。要在deploytool中显示这个示例,打开j2eetutorial/examples/ears/SimpleMessageApp.ear文件并选中SimpleMessageEJB。
指定Bean的类型和事务管理
你可经在使用New Enterprise Bean向导创建bean时指定其类型。
1、要启动这个向导,选择FileNewEnterprise Bean。
2、在向导的General对话框中,选择Message-Driven按钮。
3、在Transaction Management对话框中,你可以选择Bean-Managed,也可以选择Container-Managed。如果你选择的是Bean-Managed,那么在下面一段的第4步中,你必须选择确认类型。
设定Message-Driven Bean的特征
你可以在两个地方作这个设定:
1、在New Enterprise Bean向导中的Message-Driven Bean Settings对话框
2、bean的Message标签(参见图7-2)
这些设定包括以下内容:
1、对于Destination类型,可以选择Queue也可以选择Topic。一个队列使用点对点的消息域,至多只能有一个使用者。而一个主题使用发布-订阅的消息域,它可以有零个、一个或多个使用者。
2、在Destination组合框中,选择你创建的目的地的JNDI命名。作为一个示例,你可以参看创建队列。目的地可以是一个Queue对象,也可以是一个Topic对象;它是引入消息的发起者和发出消息的目标。
3、在Connection Factory组合框中,选择适当的对象,这可以是一个QueueConnectionFactory,也可以是一个TopicConnectionFactory。这个对象出示了J2EE组件访问消息服务的连接。
4、如果你选择了bean管理事务,那么你可能需要在Acknowledgement组合框中选择确认类型--这可能是Auto-Acknowledge(自动确认)或Duplicates-OK(OK重复)。Auto-Acknowledge类型要求会话自动确认bean在使用这个消息。而Duplicates-OK类型对消息提交的确认会迟钝一些;这个类型可能会导致一个消息的复制,但是它会减少会话的开销。
5、在JMS Message Selector区域,你可以输入一个过滤bean接收到的消息的语句。
图7-2 SimpleMessageEJB的Message标签
JMS客户端的deploytool提示
有关JMS客户端的更多的信息,请参看Java消息服务指南:
http://java.sun.com/products/jms/tutorial/index.html
设定资源索引
1、选中客户端的节点。
2、选中Resource Refs标签。
3、单击Add。
4、在Coded Name中,输入与客户端的代码中的lookup方法的参数相匹配的命名。例如,如果lookup方法的参数是java:comp/env/jms/MyQueueConnectionFactory,Coded Name就应该是jms/QueueConnectionFactory。
5、在Type中,选择与目的类型相匹配的连接factory类。
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 Names标签并输入适当的命名。例如,在这一章中所讨论的SimpleMessageApp将采用表7-1中所示的JNDI命名。
表7-1 SimpleMessageApp应用程序中所使用的JNDI命名
组件名或索引名:JNDI命名
SimpleMessageEJB:jms/MyQueue
jms/MyQueueConnectionFactory:jms/QueueConnectionFactory
jms/QueueName:jms/MyQueue