目录
1.什么是JMS规范
Java 消息服务(Java Message Service)是 java 平台中关于面向消息中间件的 API,用于在两个应用程序之间,或者分布式系统中发送消息,进行异步通信。
JMS 是一个与
具体平台无关的 API
,绝大多数 MOM
??
(Message Oriented Middleware)(面向消息中间件)提供商都对 JMS 提供了支持。接下来讲解的ActiveMQ 就是其中一个实现。
JMS可以理解为是,Java平台为MQ产商提供的一套标准。你可以类比JDBC来理解即可,JDBC就是Java为Oracle、MySQL、SqlServer等数据库产商指定的标准。
2.什么是MOM
MOM(Message Oriented Middleware)是面向消息的中间件,可以变向理解为:
消息传递和消息排队模型
。使用消息传送提供者来协调消息传送操作。MOM 需要提供 API 和管理工具。客户端使用api调用,把消息发送到由提供者管理的目的地。在发送消息之后,客户端会继续执行其他工作,并且在接收方收到这个消息确认之前,提供者一直保留该消息 (摘自:
百度百科
)
MOM通过提供
消息传递
和
消息排队
模型,它可在分布环境下扩展进程间的通信,并支持多基于 MOM 的系统通讯协议、语言、应用程序、硬件和软件平台。时下流行的MOM中间件产品有IBM的MQSeries、 BEA的MessageQ等。
3.MOM的特点
1.消息异步接受,发送者不需要等待消息接受者的响应;
2.消息可靠接受,确保消息在中间件中的可靠保存。只有接受方收到后,消息才可以被删除。
4.JMS和MOM的关联
在JMS规范出现之前,由于当时需求的出现,很多产商都开发了自己独有的消息中间件。如果我在一个系统中引入了多个消息中间件,但是由于他们都是各自一套,没有一个统一的规范,从而在当时暴露除了许多问题,比如:多个消息中间件之间的数据传递问题等
在这种情况下,2001年6月JMS规范也就诞生了。JMS是一个在 Java标准化组织(JCP)内开发的标准,是Java平台上有关面向消息中间件(MOM)的技术规范。
JMS规范最初的开发目的,是为了将Java应用程序能够访问现有的MOM系统,是为了已有的MOM系统而制定的。但是在引入规范之后,它便被许多现有的MOM供应商所采用的。
5.JMS的体系结构
6.JMS常见基本概念
1.消息传递域
JMS规范中定义了两种消息传递域:
①点对点(point-to-point)消息传递域
②PUB/SUB消息传递域(
pub
lish/
sub
scribe 发送/订阅),请看如下介绍:
点对点消息传递域
特点:
1.每个消息只能有一个消费者;
2.消息的生产者和消费者之间没有时间上的相关性。无论消费者在生产者发送消息时是否处于运行状态,都可以提取消息。
PUB/SUB消息传递域
特点:
1.每个消息可以有多个消费者;
2.生产者和消费者之间有时间上的相关性。订阅一个主题的消费者
只能消费自它订阅之后发布的消息
,订阅之前发布的消息他是收不到的,类似于微信入群操作;
3.
JMS规范允许客户创建持久订阅
,这在一定程度上降低了时间上的相关性要求。持久订阅允许消费者消费在它(消费者)未激活启动之前发送的消息。
2
.消息结构组成
JMS消息由以下三部分组成:
消息头、属性和消息体
。
消息头
消息头包含消息的 识别信息 和 路由信息 ,消息头包含的一些属性如下: |
||
属性名 |
属性名称 |
属性介绍 |
JMSDestination |
消息发送的目的地 | 主要是指Queue和Topic |
JMSDeliveryMode |
传送模式 |
有两种: 持久模式 和 非持久模式 。一条持久性的消息,如果在JMS提供者出现故障,JMS消息不会丢失,它会在服务器恢复之后继续传递。一条非持久性的消息最多会传递一次,这就意味着服务器出现故障,该消息永久丢失。 |
JMSExpiration |
消息过期时间 | 等于Destination的send方法中的timeToLive值加上发送时刻的GMT时间值。如果timeToLive值等于零,则JMSExpiration被设置为零,表示该消息永不过期。如果发送后,在消息过期时间之后消息还没有被发送到目的地,则该消息被清除。 |
JMSPriority |
消息优先级 | 从0-9十级,0-4是普通消息,5-9是加急消息。JMS不要求JMS provider严格按照这十个优先级发送消息,但必须保证加急消息要优先于普通消息到达目的地。默认是4级。 |
JMSMessageId |
消息ID | 唯一识别每个消息的标志 |
JMSTimestamp |
消息发送->接收的时间差 | 一个JMS provider在调用send()自动设置的 |
JMSCorrelationId |
用来连接到另外一个消息 | |
JMSReplyTo |
提供本消息回复消息的目的地 | |
JMSType |
消息类别的识别符 | |
JMSRedelivered |
如果一个客户端端收到了设置了JMSRedelivered属性的消息,则表示客户端可能在早些时候曾经收到过该消息,但并没有被签收(acknowledge)。如果该消息重新发送,JMSRedelivered = true 反之 JMSRedelivered = false |
属性
包含以下三种类型的属性:
1.应用程序设置或添加的属性
Message.setStringProperty(key,value)
在发送端,定义消息属性
:
message.setStringProperty("xxx","xxx");
在接收端,接受数据:
try {
Enumeration enumeration = message.getPropertyNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement().toString();
System.out.println("name:" + name + ":" + message.getStringProperty(name));
}
} catch (JMSException e) {
e.printStackTrace();
}
2.JMS定义的属性
JMS定义的属性如下:
属性名 |
属性介绍 |
JMSXUserID |
发送消息的用户标识。发送时提供商设置 |
JMSXAppID |
发送消息的应用标识。发送时提供商设置 |
JMSXDeliveryCount |
转发消息重试次数。第一次是1,第二次是2,……,发送时提供商设置 |
JMSXGroupID |
消息所在消息组的标识,客户端设置 |
JMSXGroupSeq |
组内消息的序号,第一个是1,第二个是2,……,客户端设置 |
JMSXProducerTXID |
产生消息的事务的事务标识,发送时提供商设置 |
JMSXConsumerTXID |
消费消息的事务的事务标识,接收时提供商设置 |
JMSXRcvTimestamp |
JMS转发消息到消费者的时间,接收时提供商设置 |
JMSXState |
假定存在一个消息仓库,它储存了每个消息的单独拷贝,且这些消息从原始消息发送开始,每个拷贝的状态有:1(等待)、2(准备)、3(到期)或4(保留)。由于状态与生产者和消费者无关,所以它不是由它们来提供,它只和在仓库中查找消息相关,因此JMS消息没有提供相关的API,所以由提供商设置 |
使用”JMSX”作为属性的前缀,通过如下代码,可以返回所有支持的JMSX的属性名称
try {
Enumeration names = connection.getMetaData().getJMSXPropertyNames();
while(names.hasMoreElements()){
String name = (String)names.nextElement();
System.out.println(name);
}
} catch (JMSException e) {
e.printStackTrace();
}
3.JMS提供商(Provider)特定的属性
消息体
消息体就是我们需要传递的消息内容,JMS API 定义了 5 种消息体格式,可以使用不同形式发送接收数据,并可以兼容现有的消息格式,具体如下:
消息格式 |
格式介绍 |
TextMessage |
java.lang.String 对象,如 xml 文件内容 |
MapMessage |
k/v键值对的集合,key为 String 对象,value 类型可以是 Java 任何基本类型 |
BytesMessage |
字节流 |
StreamMessage |
Java 中的输入输出流 |
OpbjectMessage |
Java 中的可序列话对象 |
Message(这个在5种之外) | 没有消息体,只有消息头和属性 |
至此,JMS基本概念介绍完了,可能看着会有点懵圈,这些只是内部的一些属性特质,你只需要简单了解一下即可。
7.JMS 的事务性会话和非事务性会话
JMS规范中,Session接口提供了commit 和 rollback 两种方法,分别用于事务的提交和回滚。
事务提交:
意味着生产的所有消息被发送,消费的所有消息被确认;
事务回滚:
意味着生产的所有消息被销毁,消费的所有消息被恢复并重新提交,除非它们已经过期。
事务性的会话,总是牵涉在事务处理中,commit 或 rollback 方法一单被调用,则意味着一个事务的结束,另一个事务的开始。关闭事务性会话,将会回滚其中的事务。
● 如何设置当前的会话是事务性还是非事务性
通过在创建 session 的时候,使用 true 或者 false 来决定当前的会话是 事务性 还是 非事务性 操作,设置如下:
//此处,通过true或者false来确定操作时 事务性 or 非事务性(第二个参数,下面会讲)
connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
● 事务性会话
在事务状态下进行发送操作,消息并未真正投递到中间件,而
只有进行 session.commit 操作之后,消息才会被真正的发送到中间件。
然后才是消费者进行消费处理。
如果是调用 session.rollback 操作,则说明当前事务期间内所发送的消息都会被取消掉
事务性会话中,消息的确认是自动进行,也就是通过session.commit()操作之后,消息便会被自动确认。
还要注意一点就是:事务性会话中,
必须保证 发送端 和 消费端 都是事务性会话。
● 非事务性会话
在非事务性会话中,消息何时被确认取决于创建会话时的
应答模式
(acknowledgement mode)。该应答模式有如下三个可选项:
Session.AUTO_ACKNOWLEDGE
当客户成功的从 receive 方法返回的时候,或者从 MessageListener.onMessage 方法成功返回的时候,会话自动确认客户收到消息
Session.CLIENT_ACKNOWLEDGE
当客户通过调用消息的 acknowledge 方法,来确认客户真正收到消息。该模式下,确认是在会话层上进行的。确认一个被消费的消息,将自动确认所有已被会话消费的消息。比如:有个for循环,如果一个消费者消费了10个消息,但是在 i==8 的时候,调用了 message.acknowledge()方法进行确认,看着是他只确认了第8个消息。但是,你会发现0~8个消息都会被确认。
Session.DUPS_ACKNOWLEDGE
消息延迟确认。指定消息提供者,在消息接收者没有确认发送时,重新发送消息。这种模式不在乎接收者收到重复的消息。
事务 | 确认机制 |
Producer(生产者) |
Customer(消费端) |
TRUE && AUTO_ACKNOWLEDGE |
session.commit() | session.commit() |
FALSE && AUTO_ACKNOWLEDGE |
不需要commit() | 不需要commit() |
FALSE && CLIENT_ACKNOWLEDGE |
发送端不需要设置 | 消费端设置,需要手动签收(message.acknowledge()手动签收) |
FALSE && DUPS_OK_ACKNOWLEDGE |
延迟确认 |
8.JMS消息的可靠性机制
JMS机制消息的可靠性,主要有两种方式:①消息确认机制 ②消息的持久化存储机制
消息确认机制
理论上来说,我们需要保证消息中间件上的消息,只有被消费者确认过以后,才会被签收。相当于我们寄一个快递出去,收件人没有收到快递,就认为这个包裹还是属于待签收状态,这样才能保证包裹能够安全送达到收件人的手里。消息中间件和寄快递的道理也是一样样的。
消息的消费,通常包含以下3个阶段:①客户接收消息 ②客户处理消息 ③消息被确认。
消息去人机制,在本文
『7.JMS 的事务性会话和非事务性会话』
中有介绍到,你可以向上查看。
消息持久化存储机制
消息的持久化存储,也就是消息发送到Broker上以后,如果Broker出现故障宕机了,那么存储在Broker上的消息不应该丢失。可以通过如下代码来设置
消息发送端
的持久化和非持久化特性,如下分情况介绍:
MessageProducer producer = session.createProducer(destination);
//DeliveryMode.NON_PERSISTENT--持久化
//DeliveryMode.NON_PERSISTENT--非持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
①非持久消息
对于非持久的消息,JMS消息发送端 不会将它存储到文件/数据库等稳定的存储介质中。也就是说
非持久化消息只是存储在内存中
,如果 JMS消息发送端 宕机了,那么内存中的非持久化消息也会丢失。
②持久化消息
对于持久化消息,消息提供者会使用
存储-转发机制
,先将消息存储到稳定的介质中,等效洗发送成功后,再做删除操作。如果 JMS消息发送端 挂掉了,那么这些为发送的消息也并不会丢失。等 JMS消息发送端 恢复正常后,会再次重新去读取这些消息,并传送给对应的消息消费者。
END