上一篇已经知道了JMS的基本操作,今天来看一下ejb3中的一种重要bean:Message Drive Bean(mdb)
如果要不断监听一个队列中的消息,通常我们需要写一个监听程序,这需要一定的开发量,而且如果要实现高并发处理,也不易扩展,而MDB则自动实现了该功能,简单点讲,MDB的应用部署到jboss后,能自动监听目标队列,一旦有消息接收,会触发onMessage事件,开发人员可以在该事件处理中扩展自己的业务逻辑.
一、定义一个MDB
1 package mdb;
2
3
4
5 import javax.ejb.ActivationConfigProperty;
6 import javax.ejb.MessageDriven;
7 import javax.jms.JMSException;
8 import javax.jms.Message;
9 import javax.jms.MessageListener;
10 import javax.jms.TextMessage;
11
12 import util.LoggerUtil;
13
14 @MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
15 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
16 @ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/queue/mytest"),
17 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
18 public class HelloWorldMDB implements MessageListener {
19
20 @Override
21 public void onMessage(Message msg) {
22 TextMessage txtMsg = null;
23 try {
24 if (msg instanceof TextMessage) {
25 txtMsg = (TextMessage) msg;
26 String msgContent = txtMsg.getText();
27 LoggerUtil.info("Received Message from queue: " + msgContent);
28 } else {
29 LoggerUtil.warning("Message of wrong type: "
30 + txtMsg.getClass().getName());
31 }
32 } catch (JMSException e) {
33 throw new RuntimeException(e);
34 }
35
36 }
37
38 }
注意该类上的注解,它表明了要监听哪个Queue(可以参考上一篇的内容,先在jboss中建好该queue),其它没什么特别的,把它放一个dynamic web中,打成war包部署到jboss上,为演示效果,部署后,先不启动该应用
附:pom.xml文件的内容
1 xml version="1.0" encoding="UTF-8"?>
2
3 <project xmlns&#61;"http://maven.apache.org/POM/4.0.0" xmlns:xsi&#61;"http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation&#61;"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5 <modelVersion>4.0.0modelVersion>
6
7 <groupId>cnblogsgroupId>
8 <artifactId>helloworld-mdbartifactId>
9 <version>0.0.1-SNAPSHOTversion>
10 <packaging>warpackaging>
11 <name>helloworld-mdbname>
12
13 <dependencyManagement>
14 <dependencies>
15 <dependency>
16 <groupId>org.jboss.bomgroupId>
17 <artifactId>jboss-javaee-6.0-with-toolsartifactId>
18 <version>1.0.7.Finalversion>
19 <type>pomtype>
20 <scope>importscope>
21 dependency>
22 dependencies>
23 dependencyManagement>
24
25 <dependencies>
26 <dependency>
27 <groupId>org.jboss.spec.javax.jmsgroupId>
28 <artifactId>jboss-jms-api_1.1_specartifactId>
29 <scope>providedscope>
30 dependency>
31 <dependency>
32 <groupId>org.jboss.spec.javax.ejbgroupId>
33 <artifactId>jboss-ejb-api_3.1_specartifactId>
34 <scope>providedscope>
35 dependency>
36 dependencies>
37
38 project>
二、测试验证
a) 可以参考上一篇JMS的内容,另建一个常规的project,向该队列发送消息(注意:仅发送,不要接收,否则消息被收走了,MDB就收不到消息了)
1 package jms;
2
3
4 import java.util.Hashtable;
5
6 import javax.jms.Connection;
7 import javax.jms.ConnectionFactory;
8 import javax.jms.Destination;
9 import javax.jms.JMSException;
10 import javax.jms.MessageConsumer;
11 import javax.jms.MessageProducer;
12 import javax.jms.Session;
13 import javax.jms.TextMessage;
14 import javax.naming.Context;
15 import javax.naming.InitialContext;
16 import javax.naming.NamingException;
17
18 public class App {
19
20 public static void main(String[] args) throws NamingException, JMSException {
21
22 final String lOOKUP_CONNECTION_FACTORY_NAME &#61; "lookup.connectionfactory.name";
23 final String lOOKUP_DESTINATION_NAME &#61; "lookup.destination.name";
24
25 ConnectionFactory connectionFactory &#61; null;
26 Connection connection &#61; null;
27 Session session &#61; null;
28 MessageProducer producer &#61; null;
29 MessageConsumer consumer &#61; null;
30 Destination destination &#61; null;
31 TextMessage message &#61; null;
32 Context context &#61; null;
33
34 try {
35 // 创建上下文&#xff08;默认会从应用的classpath下加载jndi.properties做为环境参数&#xff09;
36 context &#61; new InitialContext();
37
38 // 把环境参数取出来&#xff0c;后面会用到
39 Hashtable
40 .getEnvironment();
41
42 // 查找连接工厂
43 connectionFactory &#61; (ConnectionFactory) context.lookup(env
44 .get(lOOKUP_CONNECTION_FACTORY_NAME));
45
46 // 查找目标队列
47 destination &#61; (Destination) context.lookup(env
48 .get(lOOKUP_DESTINATION_NAME));
49
50 // 创建连接
51 connection &#61; connectionFactory.createConnection(
52 env.get(Context.SECURITY_PRINCIPAL),
53 env.get(Context.SECURITY_CREDENTIALS));
54
55 // 创建会话
56 session &#61; connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
57
58 // 创建生产者(即发送者)
59 producer &#61; session.createProducer(destination);
60
61 // 创建消费者(即接收者)
62 consumer &#61; session.createConsumer(destination);
63
64 // 开始连接
65 connection.start();
66
67 // 发送消息
68
69 message &#61; session.createTextMessage("HELLO,I AM GLAD TO SEE YOU!");
70
71 producer.send(message);
72
73 System.out.println("发送成功!");
74
75
76
77 } catch (NamingException e) {
78 e.printStackTrace();
79 } catch (JMSException e) {
80 e.printStackTrace();
81 } finally {
82 // 释放资源
83 if (context !&#61; null) {
84 context.close();
85 }
86
87 if (connection !&#61; null) {
88 connection.close();
89 }
90
91 }
92 }
93
94 }
b) 然后在jboss中,再把该应用启用起来,观察console窗口的输出:
三、xml方式配置MDB
刚才我们是用注解方式来配置MDB的&#xff0c;这种方式不需要xml配置文件&#xff0c;十分方便&#xff0c;但是也有缺点&#xff0c;配置与代码紧耦合&#xff0c;如果以后要修改queue名称&#xff0c;就得改代码&#xff0c;重新编译&#xff0c;所以jboss也提供了xml配置方式
方法&#xff1a;在META-INF(非web项目)或WEB-INF(web项目)放置一个名为jboss-ejb3.xml(这是固定名称&#xff0c;不要修改!)
内容参考下面这样&#xff1a;
1 xml version&#61;"1.0" encoding&#61;"UTF-8"?>
2 <jboss:ejb-jar xmlns:jboss&#61;"http://www.jboss.com/xml/ns/javaee"
3 xmlns&#61;"http://java.sun.com/xml/ns/javaee" xmlns:xsi&#61;"http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:c&#61;"urn:clustering:1.0"
5 xsi:schemaLocation&#61;"http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
6 version&#61;"3.1" impl-version&#61;"2.0">
7 <enterprise-beans>
8 <message-driven>
9 <ejb-name>HelloWorldQueueMDBejb-name>
10 <ejb-class>mdb.HelloWorldMDBejb-class>
11 <activation-config>
12 <activation-config-property>
13 <activation-config-property-name>destinationTypeactivation-config-property-name>
14 <activation-config-property-value>javax.jms.Queueactivation-config-property-value>
15 activation-config-property>
16 <activation-config-property>
17 <activation-config-property-name>destinationactivation-config-property-name>
18 <activation-config-property-value>jms/queue/mytestactivation-config-property-value>
19 activation-config-property>
20 <activation-config-property>
21 <activation-config-property-name>acknowledgeModeactivation-config-property-name>
22 <activation-config-property-value>Auto-acknowledgeactivation-config-property-value>
23 activation-config-property>
24 activation-config>
25 message-driven>
26 enterprise-beans>
27 <assembly-descriptor>
28 <c:clustering>
29 <ejb-name>DDBasedClusteredSFSBejb-name>
30 <c:clustered>truec:clustered>
31 c:clustering>
32 assembly-descriptor>
33 jboss:ejb-jar>
然后把HelloWorldQueueMDB类上的那一堆注解全注释掉&#xff0c;再跑下&#xff0c;顺利的话&#xff0c;也同样可以接收消息
示例源代码下载:mdb-sample.zip