ActiveMQ学习总结(5)——Java消息服务JMS详解
JMS:
Java消息服务(Java Message Service)
JMS是用于访问企业消息系统的开发商中立的API。企业消息系统可以协助应用软件通过网络进行消息交互。
JMS的编程过程很简单,概括为:应用程序A发送一条消息到消息服务器的某个目得地(Destination),然后消息服务器把消息转发给应用程序B。因为应用程序A和应用程序B没有直接的代码关连,所以两者实现了解偶。
消息驱动bean(message-driven bean)
它是专门用于异步处理java消息的组件.具有处理大量并发消息的能力.
何时使用JMS:
在某些情况下,由于SessionBean方法的执行时间比较长,这就需要异步地调用该方法,否则客户端就需要等待比较长的时间。要实现异步调用, 就需要使用消息驱动Bean。
消息驱动Bean的基本原理是客户端向消息服务器发送一条消息后,消息服务器会将该消息保存在消息队列中。在这时消 息服务器中的某个消费者(读取并处理消息的对象)会读取该消息,并进行处理。发送消息的客户端被称为消息生产者。
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类型的目标地址。
- <?xml version="1.0" encoding="UTF-8"?>
- <server>
- <mbean code="org.jboss.mq.server.jmx.Queue"
- name="jboss.mq.destination:service=Queue,name=foshanshop">
- <attribute name="JNDIName">queue/foshanshop</attribute>
- <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
- </mbean>
- </server>
(项目中用的这个:
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <server>
- <mbean xmbean-dd="xmdesc/Queue-xmbean.xml" name="jboss.messaging.destination:service=Queue,name=InstanceQueue" code="org.jboss.jms.server.destination.QueueService">
- <attribute name="JNDIName">/queues/InstanceQueue</attribute>
- <depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
- <depends>jboss.messaging:service=PostOffice</depends>
- </mbean>
- </server>
放在server\default\deploy\queues\InstanceQueue-service.xml 中)
模版可以在E:\jboss-5.1.0.GA-jdk6\jboss-5.1.0.GA\docs\examples\jms中的example-destinations-service.xml中找到。
Jboss使用一个XML文件配置队列地址,文件的取名格式应遵守*-service.xml
<attribute name="JNDIName">属性指定了该目标地址的全局JNDI名称。如果你不指定JNDIName属性,jboss会为你生成一个默认的全局JNDI,其名称由“queue”+“/”+目标地址名称组成。另外在任何队列或主题被部署之前,应用服务器必须先部署Destination Manager Mbean,所以我们通过<depends>节点声明这一依赖。
在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);
项目用:
JMS工厂和队列JNDI配在配置文件jmsqueue.properties里,内容如下:
- connectionFactoryName=ConnectionFactory
- queueName=/queues/InstanceQueue
- /**
- * 目的:读取jmsqueue.properties中消息队列的信息,初始化消息队列,提供发送消息的函数
- *
- */
- public class MsgQueueSender {
- private static final Logger logger = LoggerFactory.getLogger(MsgQueueSender.class);
- private static final MsgQueueSender ms = new MsgQueueSender();
- private Properties info = new Properties();
- /**
- * jms
- */
- private QueueConnection conn;
- private Queue que;
- private MsgQueueSender() {
- initJMSInfo();
- initMsgQueue();
- }
- /**
- * 初始化jndi队列
- *
- */
- private void initMsgQueue() {
- InitialContext iniCtx;
- try {
- iniCtx = new InitialContext();
- Object tmp = iniCtx.lookup(info.getProperty("connectionFactoryName", "ConnectionFactory"));
- QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
- conn = qcf.createQueueConnection();
- que = (Queue) iniCtx.lookup(info.getProperty("queueName", "/queues/InstanceQueue"));
- conn.start();
- } catch (Exception e) {
- logger.error("[MsgQueueSender.initMsgQueue] \u65e0\u6cd5\u8fde\u63a5\u5230\u6d88\u606f\u670d\u52a1\u5668\uff0c\u8bf7\u68c0\u67e5jms\u914d\u7f6e\u548c\u670d\u52a1\u7aef" + e.getMessage(),e);
- }
- }
- /**
- * 读取jms配置
- */
- private void initJMSInfo() {
- InputStream is = this.getClass().getClassLoader().getResourceAsStream("jmsqueue.properties");
- if (is != null) {
- try {
- info.load(is);
- } catch (IOException e) {
- logger.error("[MsgQueueSender.initJMSInfo] \u8bfb\u53d6jmsqueue.properties\u51fa\u9519\uff0c\u5c06\u4f7f\u7528\u9ed8\u8ba4\u914d\u7f6e " + e.getMessage(),e);
- }
- }
- }
- public static MsgQueueSender getInstance() {
- return ms;
- }
- public void sendTextMsg(String msg) throws JMSException{
- QueueSession session = conn.createQueueSession(false,QueueSession.AUTO_ACKNOWLEDGE);
- session.createSender(que).send(session.createTextMessage(msg));
- session.close();
- }
- public void sendObjMsg(Serializable obj) throws JMSException{
- QueueSession session = conn.createQueueSession(false,QueueSession.AUTO_ACKNOWLEDGE);
- session.createSender(que).send(session.createObjectMessage(obj));
- session.close();
- }
- }
采用消息驱动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部署时,容器将读取其中的配置信息。
- @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) {
- }
- }
项目中用:
META-INF下:
ejb-jar.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee" xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
- version="3.0">
- <display-name>msgreceiver</display-name>
- <enterprise-beans>
- <message-driven>
- <display-name>instanceMDB</display-name>
- <ejb-name>instanceMDB</ejb-name>
- <ejb-class>com.project.soa.msgreceiver.InstanceReceiver</ejb-class>
- <activation-config>
- <activation-config-property>
- <activation-config-property-name>destinationType</activation-config-property-name>
- <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
- </activation-config-property>
- <activation-config-property>
- <activation-config-property-name>destination</activation-config-property-name>
- <activation-config-property-value>/queues/InstanceQueue</activation-config-property-value>
- </activation-config-property>
- </activation-config>
- </message-driven>
- </enterprise-beans>
- </ejb-jar>
persistence.xml:
- <?xml version="1.0" encoding="UTF-8"?>
- <persistence xmlns="http://java.sun.com/xml/ns/persistence"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
- version="1.0">
- <persistence-unit name="msgreceiver-ds">
- <!-- 数据源:server\default\deploy\datasources\visesbdb-ds.xml 中jndi-name为datasources/visesbdb -->
- <jta-data-source>java:/datasources/visesbdb</jta-data-source>
- <jar-file>com.project.soa.bean-2.2.0.jar</jar-file>
- <properties>
- <property name="hibernate.hbm2ddl.auto" value="none" />
- <property name="hibernate.show_sql" value="false" />
- <property name="hibernate.format_sql" value="false" />
- </properties>
- </persistence-unit>
- </persistence>
- public class InstanceReceiver implements javax.jms.MessageListener {
- private static final Logger logger = LoggerFactory.getLogger(InstanceReceiver.class);
- @EJB(name="InstanceService")
- private InstanceService is;
- @Override
- public void onMessage(Message msg) {
- try {
- is.processMsg(((ObjectMessage)msg).getObject());
- } catch (JMSException e) {
- logger.error("[InstanceReceiver.onMessage] " + e.getMessage());
- e.printStackTrace();
- }
- }
- }
- @Stateless
- @Local ({InstanceService.class})
- public class InstanceServiceImpl implements InstanceService{
- private static final Logger logger = LoggerFactory.getLogger(InstanceServiceImpl.class);
- @PersistenceContext
- private EntityManager em;
- ...
- }
JMS中消息的 同步消费 和 异步消费
同步消费 比如
connection.start();
Message message=queueReceiver.receive();
同步消费 receive 就执行一次,并返回message对象。
同步消费中,消息的接收者会一直等待下去,直到有消息到达,或者超时。
异步消费 比如
connection.start();
receiver.setMessageListener(new MyMessageListener()); //MyMessageListener实现了MessageListener接口
System.in.read(); //这句话是为了人为的阻塞程序不然 还没接收到消息 ,程序一下子就执行完了,关闭了。
异步消费会注册一个监听器,当有消息到达的时候,会回调它的onMessage()方法,没有次数限制
ActiveMQ学习总结(5)——Java消息服务JMS详解的更多相关文章
- JAVA消息服务JMS规范及原理详解
JAVA消息服务JMS规范及原理详解 一.简介 JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应 ...
- 【转载】JAVA消息服务JMS规范及原理详解
转载:https://www.cnblogs.com/molao-doing/articles/6557305.html 作者: moyun- 一.简介 JMS即Java消息服务(Java Messa ...
- 1,Java消息服务-JMS
一,消息服务 消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建.发送.读取消息等,用于支持应用程序开发.在Java中,当两个应用程序使用JMS ...
- JMS(Java消息服务)与消息队列ActiveMQ基本使用(一)
最近的项目中用到了mq,之前自己一直在码农一样的照葫芦画瓢.最近几天研究了下,把自己所有看下来的文档和了解总结一下. 一. 认识JMS 1.概述 对于JMS,百度百科,是这样介绍的:JMS即Java消 ...
- java消息服务学习之JMS概念
JMS即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信. ...
- JMS(Java消息服务)入门教程
什么是Java消息服务 Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建.发送.读取消息等,用于支持JAVA应用程序开发.在J2EE中 ...
- Java消息服务初步学习(基于Spring In Action的整理)
几个名词 Java消息服务(Java Message Service)是一个Java标准,定义了使用消息代理的通用API. 消息代理(message broker):类似于邮局的作用,确保消息被投递到 ...
- JMS(Java消息服务)
JMS即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM:指的是利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来 ...
- MQ消息队列(2)—— Java消息服务接口(JMS)
一.理解JMS 1.什么是JMS? JMS即Java消息服务(Java Message Service)应用程序接口,API是一个消息服务的标准或者说是规范,允许应用程序组件基于J ...
随机推荐
- Android指纹识别深入浅出分析到实战
指纹识别这个名词听起来并不陌生,但是实际开发过程中用得并不多.Google从Android6.0(api23)开始才提供标准指纹识别支持,并对外提供指纹识别相关的接口.本文除了能适配6.0及以上系统, ...
- XAML实例教程系列 - 开篇(一)
XAML实例教程系列 - 开篇 2012-05-14 11:47 by jv9, 5588 阅读, 8 评论, 收藏, 编辑 去年,曾答应银光中国论坛的朋友推出一个关于XAML语言实例教程系列,帮助学 ...
- TS流解析 四
一 从TS流开始 数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video.Audio以及我们需要学习的PAT.PMT等 ...
- hibernate类或方法---备忘录
- Going Home(MCMF)
http://poj.org/problem?id=2195 题意:在一个n*m的图中,'m'代表人,'H'代表房子,人每移动一次的费用为1,求所有人移动到房子里的最小花费. 思路:最小费用最大流问题 ...
- 过河 2005年NOIP全国联赛提高组(离散化+dp)
1105 过河 2005年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在河上有一 ...
- [jzoj NOIP2018模拟10.23]
丢分主要是下面几个方面: 1.T2代码交错了,有个特判没写丢了10分 2.T1线段树加等差数列写错了(其实二维差分就可以,但我当时不会) 3.T3思考再三还是为了10分写上了主席树,还是写错了 总体评 ...
- flex中align-content属性
在flex弹性盒模型中align-content属性控制容器内多行在交叉轴上的排列方式 默认值:stretch 可用值: 属性值:flex-start 属性值:flex-end 属性值:center ...
- JavaSE综合项目演练
光阴似箭日月如梭,大家学习已经有了一段时间了,转眼间,从刚开始如何配置JDK已经到了现在快学完网络编程了.学了这么多,眼看就要进入下一个阶段了,数据库编程了,那么在进入下个阶段前,我们来完成一个综合性 ...
- WP8开发常用解决方案收集
我其实不怎么做wp的东西.但是偶尔还是会用到, 但是wp8开发的资料确实难找.特开此贴,记录一些常见的解决方案 1.水平滑动动画(比如app首次使用说明就可以用这个做) http://www.cnbl ...