ejb3: message drive bean(MDB)示例

上一篇已经知道了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="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6 
 7     <groupId>cnblogs</groupId>
 8     <artifactId>helloworld-mdb</artifactId>
 9     <version>0.0.1-SNAPSHOT</version>
10     <packaging>war</packaging>
11     <name>helloworld-mdb</name>
12 
13     <dependencyManagement>
14         <dependencies>
15             <dependency>
16                 <groupId>org.jboss.bom</groupId>
17                 <artifactId>jboss-javaee-6.0-with-tools</artifactId>
18                 <version>1.0.7.Final</version>
19                 <type>pom</type>
20                 <scope>import</scope>
21             </dependency>
22         </dependencies>
23     </dependencyManagement>
24 
25     <dependencies>
26         <dependency>
27             <groupId>org.jboss.spec.javax.jms</groupId>
28             <artifactId>jboss-jms-api_1.1_spec</artifactId>
29             <scope>provided</scope>
30         </dependency>
31         <dependency>
32             <groupId>org.jboss.spec.javax.ejb</groupId>
33             <artifactId>jboss-ejb-api_3.1_spec</artifactId>
34             <scope>provided</scope>
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 = "lookup.connectionfactory.name";
23         final String lOOKUP_DESTINATION_NAME = "lookup.destination.name";
24 
25         ConnectionFactory connectionFactory = null;
26         Connection connection = null;
27         Session session = null;
28         MessageProducer producer = null;
29         MessageConsumer consumer = null;
30         Destination destination = null;
31         TextMessage message = null;
32         Context context = null;
33 
34         try {
35             // 创建上下文(默认会从应用的classpath下加载jndi.properties做为环境参数)
36             context = new InitialContext();
37 
38             // 把环境参数取出来,后面会用到
39             Hashtable<String, String> env = (Hashtable<String, String>) context
40                     .getEnvironment();
41 
42             // 查找连接工厂
43             connectionFactory = (ConnectionFactory) context.lookup(env
44                     .get(lOOKUP_CONNECTION_FACTORY_NAME));
45 
46             // 查找目标队列
47             destination = (Destination) context.lookup(env
48                     .get(lOOKUP_DESTINATION_NAME));
49 
50             // 创建连接
51             connection = connectionFactory.createConnection(
52                     env.get(Context.SECURITY_PRINCIPAL),
53                     env.get(Context.SECURITY_CREDENTIALS));
54 
55             // 创建会话
56             session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
57 
58             // 创建生产者(即发送者)
59             producer = session.createProducer(destination);
60 
61             // 创建消费者(即接收者)
62             consumer = session.createConsumer(destination);
63 
64             // 开始连接
65             connection.start();
66 
67             // 发送消息
68 
69             message = 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 != null) {
84                 context.close();
85             }
86 
87             if (connection != null) {
88                 connection.close();
89             }
90 
91         }
92     }
93 
94 }

b) 然后在jboss中,再把该应用启用起来,观察console窗口的输出:

三、xml方式配置MDB

刚才我们是用注解方式来配置MDB的,这种方式不需要xml配置文件,十分方便,但是也有缺点,配置与代码紧耦合,如果以后要修改queue名称,就得改代码,重新编译,所以jboss也提供了xml配置方式 方法:在META-INF(非web项目)或WEB-INF(web项目)放置一个名为jboss-ejb3.xml(这是固定名称,不要修改!) 内容参考下面这样:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
 3     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:c="urn:clustering:1.0"
 5     xsi:schemaLocation="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="3.1" impl-version="2.0">
 7     <enterprise-beans>
 8         <message-driven>
 9             <ejb-name>HelloWorldQueueMDB</ejb-name>
10             <ejb-class>mdb.HelloWorldMDB</ejb-class>
11             <activation-config>
12                 <activation-config-property>
13                     <activation-config-property-name>destinationType</activation-config-property-name>
14                     <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
15                 </activation-config-property>
16                 <activation-config-property>
17                     <activation-config-property-name>destination</activation-config-property-name>
18                     <activation-config-property-value>jms/queue/mytest</activation-config-property-value>
19                 </activation-config-property>
20                 <activation-config-property>
21                     <activation-config-property-name>acknowledgeMode</activation-config-property-name>
22                     <activation-config-property-value>Auto-acknowledge</activation-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>DDBasedClusteredSFSB</ejb-name>
30             <c:clustered>true</c:clustered>
31         </c:clustering>
32     </assembly-descriptor>
33 </jboss:ejb-jar>

然后把HelloWorldQueueMDB类上的那一堆注解全注释掉,再跑下,顺利的话,也同样可以接收消息

示例源代码下载:mdb-sample.zip

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android 研究

APK安装流程详解13——PMS中的新安装流程下(装载)

而在handleReturnCode()方法里面也是调用processPendingInstall(args, ret)方法,如下:

30120
来自专栏逸鹏说道

跨站请求伪造(CSRF/XSRF)

简介   CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Ridin...

46260
来自专栏码匠的流水账

聊聊hikari连接池的maxLifetime属性及evict操作

用来标记连接池中的连接不可用,这样在borrow连接的时候,如果是标记evict的,则会继续获取连接

31220
来自专栏数据库新发现

Statspack之十四-"log file sync" 等待事件

http://www.eygle.com/statspack/statspack14-LogFileSync.htm 当一个用户提交(commits)或者回滚...

12510
来自专栏Pulsar-V

原 跨平台预编译参数

13920
来自专栏JackieZheng

Spring实战——XML和JavaConfig的混合配置

前言 看了园龄已经两年多了,再不能写完内容直接点击发布,留下一片密密麻麻的文字让别人看的头昏脑涨。所以现在每次写完主要内容后,还需要对于格式稍稍调整下。那么有没...

33660
来自专栏项勇

笔记37 | Android App优化之ANR详解

25160
来自专栏Google Dart

Flutter 构建完整应用手册-联网 顶

从大多数应用程序获取互联网上的数据是必要的。 幸运的是,Dart和Flutter为这类工作提供了工具!

14020
来自专栏Pulsar-V

跨平台编译-判断平台的预编译方法

16550
来自专栏Android知识点总结

SpringBoot-12-之Ajax跨域访问全解析

37920

扫码关注云+社区

领取腾讯云代金券