消息驱动bean可以实现成各种消息类型。最常用的是实现JMS技术(JavaMessage Service)。本章中的例子也是使用的JMS技术,因此在阅读本章之前最好对JMS的基本概念如队列和消息有些了解。
simplemessage例子应用程序简介 应用程序simplemessage有以下的组成部分:
- SimpleMessageClient:一个应用程序客户端,发送消息到队列中。
- SimpleMessageBean:一个消息驱动bean,异步的接收和处理发送到队列中的消息
图17-1显示了应用程序的结构。应用程序客户端发送消息到队列中。JMS提供者(本例中是GlassFish服务器)将消息发送给消息驱动bean的实例,该实例处理这些消息。
2011-9-5 23:32 上传
下载附件 (18.9 KB)
这个应用程序的代码可以在tut-install/examples/ejb/simplemessage目录下找到。
simplemessage应用程序客户端 SimpleMessageClient发送消息到SimpleMessageBean监听的队列。
首先我们要在客户端中注入连接工厂和队列资源:
- @Resource(mappedName="jms/ConnectionFactory")private staticConnectionFactory connectionFactory;@Resource(mappedName="jms/Queue")private staticQueue queue;
其次,客户端要创建连接、会话和消息生产者:
- connection =connectionFactory.createConnection();session =connection.createSession(false, Session.AUTO_ACKNOWLEDGE);messageProducer= session.createProducer(queue);
最后,客户端发送几条消息到队列中:
- message =session.createTextMessage();for (int i = 0;i < NUM_MSGS; i++) { message.setText("Thisis message " + (i + 1)); System.out.println("Sendingmessage: " + message.getText()); messageProducer.send(message);}
消息驱动bean类 SimpleMessageBean类表现了消息驱动bean的要求:
- 如果不使用布署描述符,那么必须使用@MessageDriven注解
- 类必须定义为public的
- 类不能是abstract或final的
- 必须有一个public的无参数的构造函数
- 不能有finalize的方法
还有一条是推荐而不是强制的要求,就是消息驱动bean应该实现其支持的消息类型的消息监听器接口。例如,支持JMSAPI实现的bean实现javax.jms.MessageListener接口。
和sessionbean以及实体类不一样,消息驱动bean没有远程或本地接口。客户端组件并不需要定位消息驱动bean并调用其方法。尽管消息驱动没有业务方法,但是还是可能有一些辅助方法会被onMessage方法调用。
注解@MessageDriven通常会包含一个mappedName元素,用来指定bean会从中消费消息的目的地的JNDI名字。对于复杂的消息驱动bean,页可以有一个activationconfig元素,包含了这个bean使用的@ActivationConfigProperty注解。
一个消息驱动bean可以被注入一个MessageDrivenContext资源。通常我们使用这个资源来调用setRollbackOnly方法来处理使用容器管理的事务的bean的异常。
SimpleMessageBean类的前几行看起来如下:
- @MessageDriven(mappedName="jms/Queue",activationConfig = { @ActivationConfigProperty(propertyName= "acknowledgeMode", propertyValue= "Auto-acknowledge"), @ActivationConfigProperty(propertyName= "destinationType", propertyValue= "javax.jms.Queue")})public classSimpleMessageBean implements MessageListener { @Resource privateMessageDrivenContext mdc; …
在使用NetBeansIDE创建消息驱动bean的时候,IDE通常会创建一组默认的@ActivationConfigProperty设置。如果不需要这些设置,可以删除它们。当然也可以添加其他的设置。
表17-1列出了常用的属性:
表格 17-1:消息驱动bean的@ActivationConfigProperty设置
属性名称
描述
acknowledgeMode
Acknowledge mode:
destinationType
javax.jms.Queue或者javax.jms.Topic
subscriptionDurability
关于持久订阅,后面的关键JMS的章节中会讨论
clientId
对于持久订阅者,这是创建连接的客户ID
subscriptionName
对于持久订阅者,这是订阅的名称
messageSelector
用来过滤消息的字符串
addressList
要进行通信的远程系统
onMessage方法 当队列收到一个消息,EJB容器会调用消息监听器方法。对于使用JMS的bean,就是MessageListener接口的onMessage方法。
一个消息监听器方法必须满足以下的规则:
- 方法必须声明成public的
- 方法不能声明成final或static的
方法onMessage被bean的容器在这个bean要处理的消息到达的时候调用。解析消息和执行相应的业务逻辑是消息驱动bean的责任。
方法onMessage有一个参数:收到的消息。
onMessage的方法签名必须满足以下规则:
- 返回类型必须是void
- 方法必须只有单独的一个参数,类型是javax.jms.Message。
在SimpleMessageBean类中,onMessage方法将收到的消息转换成一个TextMessage并显示其文本内容:
- public voidonMessage(Message inMessage) { TextMessage msg= null; try { if (inMessageinstanceof TextMessage) { msg =(TextMessage) inMessage; logger.info("MESSAGEBEAN: Message received: " + msg.getText()); } else { logger.warning("Messageof wrong type: " + inMessage.getClass().getName()); } } catch(JMSException e) { e.printStackTrace(); mdc.setRollbackOnly(); } catch(Throwable te) { te.printStackTrace(); }}
打包、布署和运行simplemessage例子 要打包、布署和运行simplemessage例子,首先进入tut-install/examples/ejb/simplemessage目录。
为simplemessage例子创建受管理的对象(AdministrateredObject) 本例子需要以下的资源:
如果你先阅读了第30章“JavaMessageService概念”,运行了其中的JMS例子,并且没有删除产生的资源,那么可以跳过这一步。
可以使用Ant的target来创建资源。在build.xml文件中定义的ant的target会使用asadmin命令。要创建本例子需要的资源,运行以下两个命令:
- ant create-cfant create-queue
这两个命令完成的事情是:
这两个命令运行的Ant的target会引用在tut-install/examples/bp-project/app-server-ant.xml文件中定义的其他的target。
使用NetBeansIDE来构建、布署和运行simplemessage应用程序在NetBeans IDE中,选择 File→Open Project
在Open Project对话框中,进入tut-install/examples/ejb目录
选择simplemessage文件夹
选中Open As Main Project选择框和Open Required Projects选择框
点击Open Project
在Projects窗口中,右键点击simplemessage工程并选择build
这样会打包应用程序客户端和消息驱动bean,然后创建名为simplemessage.ear的文件,放在dist目录中。
7. 右键点击工程并选择Run
这一步会布署工程,返回一个名为simplemessageClient.jar的家啊人文件,然后执行该jar文件。
应用程序客户端的输出会显示在Ouput窗口中,看起来如下(前面应该有应用程序客户端容器的输出)
Sending message:This is message 1
Sending message:This is message 2
Sending message:This is message 3
To see if thebean received the messages,
8. 查看<install_dir>/domains/domain1/server.log
消息驱动bean的输出显示在该服务器的日志中,输出内容看起来如下:
MESSAGE BEAN:Message received: This is message 1
MESSAGE BEAN:Message received: This is message 2
MESSAGE BEAN:Message received: This is message 3
使用Ant构建、布署和运行simplemessage应用程序 在终端窗口中,进入目录tut-install/examples/ejb/simplemessage/
要编译源文件和打包应用程序,运行命令ant
这个命令会打包应用程序客户端和消息驱动bean,然后创建一个名为simplemessage.ear的文件在dist目录中。
由于我们使用的是资源注入和注解,因此不需要为消息驱动bean和应用程序客户端创建布署描述符文件。只有当需要覆盖原文件中使用注解指定的值的时候才需要创建布署描述符。
要使用Ant来布署和运行客户端,运行命令antrun
忽略表明应用程序被布署的信息,终端窗口中的输出看起来如下:
- Sending message:This is message 1Sending message:This is message 2Sending message:This is message 3
要检查bean接收到的信息,检查<intall-dir>/domains/domain1/logs/server.log
在服务器的日志文件中,会有如下的几行信息:
- MESSAGE BEAN:Message received: This is message 1MESSAGE BEAN:Message received: This is message 2MESSAGE BEAN:Message received: This is message 3
接收消息的显示顺序可能和发送消息的顺序不一致。
移除创建的被管理对象(administeredobjects) 当运行完这个例子之后,可以使用以下的命令来删除我们创建的连接工厂和队列:
- ant delete-cfant delete-queue