分布式消息通信 - JMS

JMS 规范

JMS 指定了消息结构、编程模型、和一套控制消息传送操作的规则和语义。

JMS 消息结构

按照 JMS 规范,一个消息包括三部分:标题、属性和主体。

  • 标题:标题指定了消息的 JMS 属性(目标、持久与否、有效期及优先级),这些属性控制了消息传送系统如何传送消息。
  • 属性:属性(可以看作标题的扩充)为可选项,应用程序可以使用属性提供的值根据各种选择标准来过滤消息,属性为可选项。
  • 消息主体:消息主体包括要交换的实际数据,JMS 支持六种主体类型,包括一种基本消息类型(Message)和五种子类型(BytesMessage、MapMessage、ObjectMessage、StreamMessage 和 TextMessage)。

JMS 编程模型

在 JMS 编程模型中,JMS 客户机(组件或应用程序)通过 JMS 消息服务交换消息。消息生成方将消息发送至消息服务,消息使用方则从消息服务接收这些消息。这些消息传送操作是使用一组实现 JMS 应用编程接口 (API) 的对象(由 JMS 提供者提供)来执行的。

JMS 编程对象

在 JMS 编程模型中,JMS 客户机使用 ConnectionFactory 对象创建一个连接,向 JMS 消息服务发送消息以及从 JMS 消息服务接收消息均是通过此连接来进行。Connection 是 JMS 客户机与消息服务的活动连接。创建连接时,将分配通信资源以及验证客户机。这是一个相当重要的对象,大多数客户机均使用一个连接来进行所有的消息传送。

连接用于创建会话。Session 是一个用于生成和接收消息的单线程上下文。它用于创建发送和接收消息的生成方和使用方,并为所发送的消息定义发送顺序。通过大量的确认选项或事务(可由分布式事务管理器来管理),会话支持可靠的传送。

JMS 客户机使用 MessageProducer 向指定的物理目标(在 API 中表示为目标对象)发送消息。消息生成方可指定一个默认传送模式(持久性消息或非持久性消息)、优先级和有效期值,以控制生成方向物理目标发送的所有消息。

同样,JMS 客户机使用 MessageConsumer 对象从指定的物理目标(在 API 中表示为目标对象)接收消息。消息使用方可使用消息选择器,借助它,消息服务可以仅向消息使用方发送与选择标准匹配的那些消息。

消息使用方可以支持同步或异步消息接收。异步接收可通过向使用方注册 MessageListener 来实现。当会话线程调用 MessageListener 对象的 onMessage() 方法时,客户机将接收到消息。

被管理对象

JMS 提供了两种通用类型的被管理对象。连接工厂对象和目标对象。虽然两者都用于封存提供者特有的信息,但在 JMS 客户机中,它们的用途却有很大的差异。连接工厂用于创建至消息服务器的连接,而目标对象用于标识 JMS 消息服务使用的物理目标。

JMS 消息传送

消息传送模型

JMS 支持两种截然不同的消息传送模型:点对点模型和发布/订阅模型。

  • 点对点(队列目标):消息从一个生成方传送至一个使用方。在此传送模型中,目标是一个队列。消息首先被传送至队列目标,然后根据队列传送策略从此队列将消息传送至向此队列进行注册的某一个使用方,一次只传送一条消息。可以向队列目标发送消息的生成方的数量没有限制,但每条消息只能发送至、并由一个使用方成功接收。如果没有已向队列目标注册的使用方,队列将保留它收到的消息,并在某个使用方向该队列进行注册时将消息传送给该使用方。
  • 发布/订阅(主题目标):消息从一个生成方传送至任意数量的使用方。在此传送模型中,目标是一个主题。消息首先被传送至主题目标,然后传送至所有已订阅此主题的活动使用方。可以向主题目标发送消息的生成方的数量没有限制,并且每个消息可以发送至任意数量的订阅使用方。主题目标也支持长期订阅的概念。长期订阅表示使用方已向主题目标进行注册,但在消息传送时此使用方可以处于非活动状态。当此使用方再次处于活动状态时,它将接收此信息。如果没有已向主题目标注册的使用方,主题不保留其接收到的消息,除非有非活动使用方注册了长期订阅。
统一域 点对点域 发布/订阅域
Destination(Queue 或 Topic) Queue Topic
ConnectionFactory QueueConnectionFactory TopicConnectionFactory
Connection QueueConnection TopicConnection
Session QueueSession TopicSession
MessageProducer QueueSender TopicPublisher
MessageConsumer QueueReceiver TopicSubscriber

可靠消息传送

JMS 定义了两种传送模式:持久性消息和非持久性消息。

  • 持久性消息:保证这些消息只被传送一次和成功接收一次。对于这些消息,可靠性是优先考虑的因素。
  • 非持久性消息:保证这些消息最多被传送一次。对于这些消息,可靠性并非主要的考虑因素。

对于持久性消息,确保可靠性有两个方面:一个是确保至目标和出自目标的持久性消息传送成功;另一个就是确保在将持久性消息传送至使用方前,消息服务没有丢失持久性消息。

可靠的消息传送的关键在于确保至目标和出自目标的持久性消息传送成功。可通过 MQ 会话支持的两个通用机制:确认或事务(可以是本地事务或分布式事务)来实现此目的。

  • 确认:可以将会话配置为使用确认来确保可靠传送。对于生成方,这意味着在生成方的 send() 方法返回前,消息服务确认已向其目标发送持久性消息。对于使用方,这意味着在消息服务从该目标删除持久性消息前,客户机确认从此目标发出的持久性消息已传送并已接收。

  • 本地事务:也可以将会话配置为事务,这样,可以将一个或多个消息的生成和/或接收组成原子单元,也就是事务。JMS API 提供了启动、提交或回滚事务的方法。

  • 分布式事务:支持分布式事务是指消息传送客户机可通过 JTA 定义的 XAResource 接口参与分布式事务。此接口定义了实现两阶段提交的许多方法。