什么是MOM

MOM(Message Oriented Middleware)是面向消息的中间件,使用消息传送提供者来协调消息传送操作。MOM 需要提供 API 和管理工具。客户端使用 API 调用,把消息发送到由提供者管理的目的地。在发送消息之后,客户端会继续执行其他工作,并且在接收方收到这个消息确认之前,提供者一直保留该消息。

目前主流标准有 JMS(Java Message Service)、AMQP(Advanced Message Queuing Protocol)和STOMP(Streaming Text Oriented Messaging Protocol)。

JMS 是 Java 平台上的面向接口的消息规范,是一套 API 标准,并没有考虑异构系统。AMQP 是一个面向协议的,跟语言平台无关的消息传递应用层协议规范。STOMP 是流文本定向消息协议,是一种为MOM设计的简单文本协议。

基于 MOM 的系统允许通过异步交换消息来进行通信 。

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_API

面向消息的中间件使用消息传输提供者来协调消息传输操作。MOM 系统的基本元素是客户端、 API 、消息和 MOM 提供者,服务端。使用 MOM 系统,客户端通过 API 调用,将消息发送到消息队列服务器的目的地。消息传输提供者负责传递消息。在发送消息之后,客户端会继续执行其他工作,并在服务端确认该消息之前,消息队列服务器上一直保留该消息。

MOM 系统的优点

  • MOM 系统提供了消息异步接收,消息生产者不需要等待消息消费者的响应。
  • MOM 系统提供了系统之间解耦的可能性。
  • MOM 系统提供了消息的可靠传递,确保消息在中间件可靠保存。
  • MOM 系统通过添加管理界面,可以监视和调整性能。
MOM 系统的缺点
  • 引入MOM 中间件后,使系统的复杂度提高了,它体现在以下几个方面:
  1. 引入MOM 中间件之后,需要对MOM 服务器做维护,MOM 宕机后,客户端和服务端直接的数据交互就断了,因此保证消息队列的高可用是一个问题,使得系统变得复杂
  2. 引入MOM 中间件之前,客户端直接调用服务端的接口;引入MOM 之后,需要保证客户端发送的消息没有重复消费,没有丢失,以及保证消息的顺序性,使得系统变得复杂
  3. 对于数据敏感的业务来说,会有数据一致性的问题,解决一致性问题,使得系统变得复杂

但是面对高并发的业务场景,必须要使用面向消息的中间件系统,以达到异步、解耦、流量削峰的目的。

JMS 规范
JMS 简介

JMS(Java Message Service)是 Java 的消息服务,JMS API 是一个 Java 平台的 API,是一个消息服务的标准,大多数面向消息的中间件MOM(Message Oriented Middleware )都对 JMS 提供了支持。JMS 是 API 标准,而不是协议标准,用于在两个应用程序之间或分布式系统中发送消息,进行异步通信。其中,ActiveMQ 就是基于 JMS 规范实现的。

JMS 规范的目的是为了使得 Java 应用程序能够访问现有 MOM 消息中间件系统而形成的一套统一的标准规范,解决不同消息中间件之间的协作问题。

在创建 JMS 规范时,有以下设计精髓:

  • 消息传输提供供者的概念,比如ActiveMQ 的 broker
  • 不同的消息传递域,例如点对点消息传输和发布/订阅消息传输
  • 用于接收同步和异步消息的工具
  • 对消息传递可靠性的支持
  • 常见消息格式,例如流、文本和字节
JMS API 体系结构

连接、会话、目的地、消息、消息生产者、消息消费者是构成 JMS 应用程序的基本对象,体现架构图如下:

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_客户端_02

为了发送或接收消息,JMS 客户端必须先连接到 JMS 提供者(即消息代理),此连接在客户端与代理之间打开一个通信通道。接下来,客户端必须设置一个用来创建、生成和使用消息的会话。可以将该会话视为定义客户端与代理之间的特定对话的消息流。客户端本身就是消息生产者或消息使用方。消息生成方向消息代理所管理的目的地发送一条消息。消息使用方访问该目的地使用此消息。

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_消息传递_03

JMS 的消息传递域

JMS规范中定义了两种消息传递域

  1. 点对点(point to point)消息传递域
  2. 发布/订阅(publish-subscribe)消息传递域
点对点(point to point)消息传递域

使用队列(Queue)作为消息通信载体,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时;消息的生产者和消费者之间没有服务启动运行的相关性,也就是说当生产者生成消息的时候,不管消费者是否处于运行状态,只要消费者程序运行,消息队列里有消息,那么消费者都可以提取消息。

点对点的消息模型如下:

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_API_04

发布/订阅(publish-subscribe)消息传递域

发布订阅模型(Pub/Sub) 使用主题(Topic)作为消息通信载体,每个消息可以有多个消费者,类似于广播模式;生产者发布一条消息,该消息通过主题传递给所有的订阅者,一般情况下在一条消息广播之后才订阅的用户则是收不到该条消息的,如果消费者创建了持久订阅,那么允许消费者消费它未启动时生产者已经发布的消息。

发布/订阅的消息模型如下:

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_API_05

JMS 消息结构组成

Message 消息包括消息头和消息体以及其它的扩展属性,消息主体用来保存数据;消息头中包含代理路由和管理消息所需的信息;属性可以由客户端应用程序或提供者定义,以满足处理消息的需要。

消息头(Header)

消息头包含消息的识别信息和路由信息,每个消息头字段都有相应的 getter 和 setter 方法,所有消息类型的这部分格式都是一样的。

消息头包含一些标准的属性如下:

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_API_06

消息体(Body)
消息体就是我们需要传递的消息内容,JMS 定义了五种不同的消息正文格式,以及调用的消息类型 :

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_消息传递_07

属性(Properties)

如果需要除消息头字段以外的值,那么可以使用消息属性,有三种类型的属性:分为自定义属性,JMS 定义的属性和提供者特定的属性 。

自定义属性

可以使用任何 Java 类型来自由定义任何属性,发送者可以使用set方法设置属性,消费者可以使用get方法获取发送者设置属性的值。

  • JMS 定义的属性

JMS 规范为 JMS 定义的属性,保留 JMSX 属性名称前缀,这些属性是可选的:

深入探索MOM世界:揭秘JMS规范,解锁消息传递的无限可能!_消息传递_08

只有 JMSXGroupID 和 JMSXGroupSeq 需要所有 JMS 提供者的支持,也就是我们经常说的消息分组。这些属性的设置 JMS 规范没有提供对应的 getter 和 setter 方法, 在为这些属性赋值时,必须使用自定义属性方法来设置它们,如下:

message.setStringProperty("JMSXGroupID","order_queue-1001");
message.setIntProperty("JMSXGroupSeq",10010001);
  • 1.
  • 2.

通过下面这段代码可以返回所有连接支持的 JMSX 属性的名字:

Enumeration<String> names = connection.getMetaData().getJMSXPropertyNames();
while(names.hasMoreElements()){
    String name = names.nextElement();
    System.out.println(name);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
提供者特定的属性

每个 JMS 提供者即 JMS provider 都可以定义一组私有属性,这些属性可以由客户端或提供者自动设置。提供者特定的属性必须以前缀JMS开头,后面紧接着是属性名称(JMS<vendor-property-name>)。

提供者特定的属性,其作用就是支持各厂商的私有特性,这种属性一般用不到。