EJB3.0 EJB开发消息驱动bean
(7)EJB3.0 EJB开发消息驱动bean JMS
一: Java消息服务(Java Message Service)
二:jms中的消息
消息传递系统的中心就是消息。一条 Message 由三个部分组成:
头(header),属性(property)和主体(body)。
消息有下面几种类型,他们都是派生自 Message 接口。
StreamMessage:一种主体中包含 Java 基元值流的消息。其填充和读取均按顺序进行。
MapMessage:一种主体中包含一组名-值对的消息。没有定义条目顺序。
TextMessage:一种主体中包含 Java字符串的消息(例如,XML消息)。
ObjectMessage:一种主体中包含序列化 Java 对象的消息。
BytesMessage:一种主体中包含连续字节流的消息。
消息的传递模型
JMS 支持两种消息传递模型:点对点(point-to-point,简称 PTP)和发布/订阅(publish/subscribe,简称 pub/sub)。这两种消息传递模型非常相似,但有以下区别:
PTP 消息传递模型规定了一条消息只能传递给一个接收方。 采用javax.jms.Queue 表示。
Pub/sub 消息传递模型允许一条消息传递给多个接收方。采用javax.jms.Topic表示
这两种模型都通过扩展公用基类来实现。例如:javax.jms.Queue 和javax.jms.Topic 都扩展自javax.jms.Destination 类。
点对点模型:
发布或订阅模式:
三: 配置目标地址
开始JMS编程前,我们需要先配置消息到达的目标地址(Destination),因为只有目标地址存在了,我们才能发送消息到这个地址。由于每个应用服
务器关于目标地址的配置方式都有所不同,下面以jboss为例,配置一个queue类型的目标地址。
本文用的配置地址:将这个文件在 jboss中发布。
< xml version="1.0" encoding="UTF-8" >
<server>
<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=itmQueue">
<attribute name="JNDIName">queue/itmQueue</attribute>
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
<mbean code="org.jboss.mq.server.jmx.Topic"
name="jboss.mq.destination:service=Topic,name=itmTopic">
<attribute name="JNDIName">topic/itmTopic</attribute>
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
</server>
目标地址itmQueue发布前,必须先发布目标地址的管理器DestinationManager,所以采用依赖元素depends申明这个依赖。
它发布的过程,和数据源和EJB都是一样的。只需把它拷贝到JBoss的server/default/deploy目录下就行了。 拷贝完后就可以在JBoss控制台看到信息:
[itcastQueue] Bound to JNDI name: queue/itmQueue
说明目标地址itcastQueue绑定了queue/itcastQueue这个监单名称里面去。
queue/itcastQueue这个监单名称前面并没有java:,也就是说这个名称是在全局命名空间里面的,它可以被外部应用进行访问。
发布完后也可以进入JBoss管理后台,找到jboss.mq.destination这个栏目,找到刚才所发布的目标地址 name=itcastQueue.service=Queue,点击进去可以看到里面的一些信息。
四:当目标地址建立好了之后,就可以进行消息的发送。
在java类中发送消息,一般发送消息有以下步骤:
(1) 得到一个JNDI初始化上下文(Context)
InitialContext ctx = new InitialContext();
(2) 根据上下文查找一个连接工厂 QueueConnectionFactory 。该连接工厂是由JMS提供的,不需我们自己创建,每个厂商都为它绑定了一个全局JNDI,我们通过它的全局JNDI便可获取它;
QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
(3) 从连接工厂得到一个连接 QueueConnection
conn = factory.createQueueConnection();
(4) 通过连接来建立一个会话(Session);
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
这句代码意思是:建立不需要事务的并且能自动确认消息已接收的会话。
(5) 查找目标地址:
例子对应代码:Destination destination = (Destination ) ctx.lookup("queue/foshanshop");
(6) 根据会话以及目标地址来建立消息生产者MessageProducer (QueueSender和TopicPublisher都扩展自MessageProducer接口)
例子对应代码:
MessageProducer producer = session.createProducer(destination);
TextMessage msg = session.createTextMessage("您好,这是我的第一个消息驱动Bean");
producer.send(msg);
第一种方式:
package cn.itm.app;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
public class QueueSender {
public static void main(String[] args){
try {
InitialContext ctx = new InitialContext();
// 查找 QUeue类型的连接工厂。
QueueConnectionFactory factory = (QueueConnectionFactory) ctx
.lookup("QueueConnectionFactory");
QueueConnection conn = factory.createQueueConnection();
// 创建一个 到该地址的会话, 第二个参数:消息的确认模式,这里用自动的确认模式。
QueueSession session = conn.createQueueSession(false,
QueueSession.AUTO_ACKNOWLEDGE);
// 目标地址的连接名称。
Destination destination = (Destination) ctx
.lookup("queue/itmQueue");
// 建立消息的发送者。
MessageProducer producer = session.createProducer(destination);
TextMessage msg = session.createTextMessage("您好,这是我的第一个消息驱动Bean");
producer.send(msg);
// System.out.println(msg);
session.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行QueueSender,往目标地址发送一条消息。
消息发送完后,就可以编写消息的接收者。
采用消息驱动Bean (Message Driven Bean)接收消息。
消息驱动Bean(MDB)是设计用来专门处理基于消息请求的组件。它和无状态Session
Bean一样也使用了实例池技术,容器可以使用一定数量的bean实例并发处理成百上千个JMS消息。正因为MDB具有处理大量并发消息的能力,所以非常
适合应用在一些消息网关产品。如果一个业务执行的时间很长,而执行结果无需实时向用户反馈时,也很适合使用MDB。如订单成功后给用户发送一封电子邮件或
发送一条短信等。
一个MDB通常要实现MessageListener接口,该接口定义了onMessage()方法。Bean通过它来处理收到的JMS消息。
package javax.jms;
public interface MessageListener {
public void onMessage(Message message);
}
当容器检测到bean守候的目标地址有消息到达时,容器调用onMessage()方法,将消息作为参数传入MDB。MDB在onMessage()中决
定如何处理该消息。你可以使用注释指定MDB监听哪一个目标地址(Destination)。当MDB部署时,容器将读取其中的配置信息。
消息驱动Bean (Message Driven Bean):
@MessageDriven(activationConfig =
{
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/foshanshop"),
@ActivationConfigProperty(propertyName="acknowledgeMode",
propertyValue="Auto-acknowledge")
})
public class PrintBean implements MessageListener {
public void onMessage(Message msg) {}
}
package cssage;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/itmQueue"),
// 当我们使用的是容器来管理事务的时候,acknowledgeMode这个属性设置也没什么意义,
// 这里可以省略掉 自动确认模式,也可以不要,。
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
public class MessageDrivenBean implements MessageListener {
@Override
public void onMessage(Message message) {
/**
* 当容器检测到MessageDrivenBean这个消息驱动bean它所监听的目标地址有消息到达的时候,
* 它会把消息作为输入参数,传入消息驱动bean的onMessage方法,在方法里面就可以对消息进行处理 那么容器它是怎么知道消息驱动bean
* 它所监听的目标地址,这时候需要用注解来告诉容器: 这个消息驱动bean它监听的是哪个 目标地址,还有这个目标地址的类型
*/
// 因为发送的消息 是文本类型:
TextMessage msg = (TextMessage) message;
try {
System.out.println(msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
jndi:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost\:1099
消息驱动bean开发完后,就要对它进行打包,部署。
编写build.xml,然后把消息驱动bean发布到JBoss中。当消息驱动bean成功发布完之后,正常情况下会在控制台中把刚才发送的消息打印到控制台中。
消息驱动bean一旦布署到JBoss中的时候,容器就会根据bean所配置的信息到目标地址获取到消息,然后传入到onMessage方法里面去,执行方法里面的内容。
通过这个例子也可以发现,JMS编程可以允许发送者和接收方可以不同时在线。也就是说发送消息的时候,消息接收方可以不在线。只要消息接收方登录到系统的
时候,它也可以获取到消息。而且消息接收方和消息发送方它们之间并没有代码的直接关联。两者之间实现很好的解耦。
build.xml
< xml version="1.0" encoding="UTF-8" >
<!-- name中指的是项目名称。basedir指的是与build.xml的同级目录 -->
<!--
(1)basedir 代表 项目所在的路径。
-->
<project name="MessageDriverBean" basedir=".">
<!-- 项目源文件 所在的目录。-->
<property name="src.dir" value="${basedir}\src" />
<!-- 指向环境变量中系统变量 -->
<property environment="env" />
<!-- 指向系统变量中的JBOSS_HOME变量 ,可以得知JBOSS_HOME的安装地址 -->
<property name="jboss.home" value="${env.JBOSS_HOME}" />
<property name="jbosnfig" value="default" />
<!-- class文件存在的目录 -->
<property name="build.dir" value="${basedir}\build" />
<path id="build.classpath">
<!-- 包含 client路径下的所有 jar文件-->
<fileset dir="${jboss.home}\client">
<include name="*.jar" />
</fileset>
<pathelement location="${build.dir}" />
</path>
<target name="prepare">
<delete dir="${build.dir}" />
<mkdir dir="${build.dir}" />
</target>
<!-- depends="prepare" 确保 先执行上面的代码,在执行下面的代码 -->
<target name="compile" depends="prepare" description="编译">
<!-- class 存放到 destdir这个目录。在调用javac 这个目录就必须建立起来-->
<javac srcdir="${src.dir}" destdir="${build.dir}" >
<classpath refid="build.classpath" />
</javac>
</target>
<target name="ejbjar" depends="compile" description="创建EJB发布包">
<jar jarfile="${basedir}\${ant.project.name}.jar">
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
</jar>
</target>
<target name="deploy" depends="ejbjar" description="发布ejb">
<copy file="${basedir}\${ant.project.name}.jar" todir="${jboss.home}\server\${jbosnfig}\deploy" />
</target>
<target name="undeploy" description="卸载ejb">
<delete
file="${jboss.home}\server\${jbosnfig}\deploy\${ant.project.name}.jar" />
</target>
</project>
关于Queue类型的发送和接收就已经介绍完了,现在开始学习下关于topic类型的消息发送和接收。也就是发布/订阅传递模型的消息发送和接受。在这种模型里,消息是可以被多个接收方进行接受的。
第二种方式:发布/订阅传递模型的消息发送和接受。
package cn.itm.app;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.naming.InitialContext;
public class TopicSender {
public static void main(String[] args){
try {
InitialContext ctx = new InitialContext();
TopicConnectionFactory factory = (TopicConnectionFactory) ctx
.lookup("TopicConnectionFactory");
TopicConnection conn = factory.createTopicConnection();
TopicSession session = conn.createTopicSession(false,
QueueSession.AUTO_ACKNOWLEDGE);
Destination destination = (Destination) ctx
.lookup("topic/itmTopic");
MessageProducer producer = session.createProducer(destination);
TextMessage msg = session.createTextMessage("您好,这是我的第一个topic消息");
producer.send(msg);
session.close();
conn.close();
System.out.println("发送完");
} catch (Exception e) {
e.printStackTrace();
}
}
}
package cssage;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/itmTopic")
})
public class ReceiveBean implements MessageListener {
@Override
public void onMessage(Message message) {
TextMessage msg = (TextMessage) message;
try {
System.out.println(this.getClass() + msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
package cssage;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/itmTopic")
})
public class ReceiveOtherBean implements MessageListener {
@Override
public void onMessage(Message message) {
TextMessage msg = (TextMessage) message;
try {
System.out.println(this.getClass() + msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
操作步骤:
首先启动jboss,接着把itm-service.xml 发布。
接着:build.xml发布。
这两个消息驱动 bean都开发完了,它们两个都会从目标地址里面获取到消息,现在对它进行发布。
但是在控制台并没有看到刚才发送的topic消息,那是因为对于topic类型的消息,如果当时接收方没有监听topic类型的消息的话,那么它就获取不
到消息。尽管我们把它布署到JBoss中,因为它当时并没有监听topic这个目标地址,所以它是无法得到消息的。
现在执行下TopicSender.java,就会看见这两个消息驱动bean获取到消息了。控制台输出:
INFO [STDOUT] class cssage.ReceiveOtherBean您好,这是我的第一个topic消息
INFO [STDOUT] class cssage.ReceiveBean您好,这是我的第一个topic消息
也就证明,对于发布/订阅传递模型,多个接收方都可以得到这条消息
回头再测试下Queue类型的发送,运行QueueSender.java,对于queue类型的发送,它是一个消息只允许一个接收方进行接收。
原文:http://www.educity.cn/wenda/357315.html
EJB3.0 EJB开发消息驱动bean的更多相关文章
- EJB_开发消息驱动bean
开发消息驱动bean Java消息服务(Java MessageService) Java 消息服务(Java Message Service,简称 JMS)是用于访问企业消息系统的开发商中立的API ...
- 菜鸟调错(二)——EJB3.0部署消息驱动Bean抛javax.naming.NameNotFoundException异常
在部署EJB的消息驱动Bean时遇到了如下的错误: ERROR [org.jboss.resource.adapter.jms.inflow.JmsActivation] (WorkManager(2 ...
- Intellij IDEA 创建消息驱动Bean - 接收JMS消息
除了同步方式的调用之外,有时还需要异步调用,用来处理不需要即时处理的信息,例如短信.邮件等,这需要使用EJB中的独特组件——消息驱动Bean(Message-Driven Bean,MDB),它提供了 ...
- JMS和消息驱动Bean(MDB)
一.说明 本示例使用的ActiveMQ作为消息中间件,服务器为Glassfish,使用JMS发送消息,在MDB接收到消息之后做打印输出. 二.ActiveMQ安装配置 1.安装console war包 ...
- 消息驱动Bean
消息驱动bean是专门用来处理基于消息请求的组件.MDB负责处理消息,而EJB容器则负责处理服务(事务,安全,并发,消息确认等),使Bean的开发者集中精力在处理消息的业务逻辑上. 消息驱动Bean. ...
- 消息驱动bean(MDB)实例
到眼下为止前面介绍的有关JavaEE的东西都是同步的.也就是说调用者调用某个方法.那么这种方法必须马上运行并返回运行结果. 用官方一些的语言来说就是"client通过业务接口调用一个方法,在 ...
- 3.开发Java消息驱动bean实例代码
java消息服务(JMS)是用于访问企业消息系统的开发商中立的API.企业消息系统可以协助应用软件通过网络进行消息交互.应用程序A发送一条消息到消息服务器的某个目的地(Destination),然后消 ...
- J2EE的十三个技术——EJB之消息驱动JMS
JMS--Java Message Service JAVA的消息服务,消息可实现两端通信. 用于访问面向消息中间件的标准api,他提供与厂商无关的访问方法,以访问消息收发服务. 特点:即使其中一方不 ...
- EJB开发第二期---开发具有本地接口的无状态Bean
一.EJB中的bean 1.1 EJB中bean分类 会话bean(session bean) 负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都 ...
随机推荐
- 面试总结之数据结构(Data Structure)
常用数据结构及复杂度 http://www.cnblogs.com/gaochundong/p/3813252.html 常用数据结构的时间复杂度 Data Structure Add Find De ...
- ps -ef 输出具体含义
ps -ef 输出具体含义 UID PID PPID C STIME TTY TIME CMD 各相关信息的意义: UID 程序被该 UID 所拥有 PID 就是这 ...
- ROS使用国内的DDNS服务
未测试.转载余松老师的作品 虽然RouterOS 加入了cloud功能,但最近在配置RB2011的时候发现不好使,更新域名后无法正确解析到我的IP地址,虽然在cloud的public address中 ...
- Vue 目录结构分析 数据绑定 绑定属性 循环渲染数据 数据渲染
一.目录结构分析 node_modules 项目所需要的各种依赖 src 开发用的资源 assets 静态资源文件 App.vue 根组件 main.js 配置路由时会用 .babelrc 配置文件 ...
- solr精确查询,查询关键字分词后,指定满足匹配所有
一.solr查询,查询配置了查询分词器的字段,默认会对查询关键字做分词处理 1.如查询关键字F1501ZY000011,使用solr7自带的中文分词器,默认会分词为:f,1501,zy,000011 ...
- Linux nohup和&的功效
nohup和&究竟有啥区别?不少同学进行了回复,但并不是所有同学都理解得全对,今天把自己挖的坑自己填了. 测试代码如下: 是一个输出hello与循环轮数的死循环程序,每输出一行就休眠1秒. 使 ...
- Python之分布式监控系统开发
为什么要做监控? –熟悉IT监控系统的设计原理 –开发一个简版的类Zabbix监控系统 –掌握自动化开发项目的程序设计思路及架构解藕原则 常用监控系统设计讨论 Zabbix Nagios 监控系统需求 ...
- firemonkey Grid自定义
http://stackoverflow.com/questions/28893564/memory-leak-on-tstringgrids-ondrawcolumncell-event http: ...
- 怎样给oracle数据库的用户解锁
找到并进入运行窗口:(可以用windows+r快捷键哦)输入sqlplus命令:如图 进入新窗口后使用scott/tiger用户和密码进行登录会发现登录不成功:如图 这时我们可以使用syste ...
- XML解析的二种方法之dom解析
XML解析的二种方法:dom解析和sax解析 文件大小 存储位置 读取速度 dom解析 小文件 放在内存中 快 sax解析 ...