Java 消息服务 (JMS) 基础
Message Queue 是一种实现了 Java 消息服务 (JMS) 开放标准的企业消息传送系统:它是 JMS 提供者。因此,JMS 概念是理解 Message Queue 服务工作方式的基础。
JMS 规范规定了一套管理可靠异步消息传送的规则和语义。该规范定义了消息结构、编程模型和 API。
本节说明了理解本书其余各章所需的 JMS 概念和术语。涵盖下列主题:
在 Message Queue 中,数据是使用 JMS 消息进行交换的。根据 JMS 规范,生产者客户机创建的消息包括三部分:标题、属性和主体。
每条 JMS 消息都必须具有标题。标题字段包含用于路由和识别消息的值。
有关 JMS 定义的标题字段的信息,请参见 Message Queue Developer's Guide for Java Clients 或 Message Queue Developer's Guide for C Clients。可以通过这些标题字段定义消息的目标、到期时间及其优先级等。
消息可以包含称作属性的可选标题字段。它们是以属性名和属性值对的形式指定的。可以将属性视为消息标题的扩展,其中可以包括以下信息:创建数据的进程、数据的创建时间以及每条数据的结构。JMS 提供者也可以添加影响消息处理的属性,如是否应压缩消息或如何在消息生命周期结束时废弃消息。
JMS 提供者可以将消息属性用作选择器,以对消息进行排序和路由。生产者客户机可以在消息中放置特定于应用程序的属性;而消费者客户机可以选择只接收具有特定属性值的消息。例如,消费者客户机可能只请求获得有关新泽西州兼职雇员工资单的消息。不符合指定的选择标准的消息将不会传送给该客户机。
选择器简化了消费者客户机的工作,并消除了向不需要这些消息的客户机传送消息的开销。不过,由于要处理选择标准,它们也会增加消息服务的一些开销。在 JMS 规范中对消息选择器语法和语义进行了简要说明。
JMS 消息的类型决定其主体的内容,如表 1-1 中所示。
JMS 编程模型支持异步消息传送服务体系结构:JMS 客户机通过 JMS 消息服务交换消息。JMS 提供者提供执行 JMS 消息传送所需的对象;这些对象用于实现 JMS 应用程序编程接口 (API)。
本节说明 JMS 消息传送所需的编程对象,并介绍用于发送和接收消息的传送模型(点对点及发布/订阅)。
图 1-3 中显示了用于设置 JMS 客户机以进行消息传送的对象。
在 JMS 编程模型中,JMS 客户机使用连接工厂对象 (ConnectionFactory) 创建一个连接,向 JMS 消息服务器发送消息以及从 JMS 消息服务器接收消息均通过此连接来进行。连接对象 (Connection) 表示客户机与消息服务器之间的活动连接。
创建连接时,将分配通信资源以及验证客户机。这是一个相当重要的对象,大多数客户机均使用一个连接来进行所有的消息传送。
该连接用于创建会话对象 (Session)。会话是一个用于生成和使用消息的单线程上下文。它用于创建消息以及发送和接收消息的生产者和消费者,并为所传送的消息定义发送顺序。会话通过大量确认选项或通过事务来支持可靠传送。
客户机使用消息生产者对象 (MessageProducer) 向指定的物理目标(在 API 中由目标对象表示)发送消息。消息生产者可指定一个默认的消息标题值,例如,传送模式(持久性与非持久性)、优先级和有效期,以控制生产者向物理目标发送的所有消息。
同样,客户机使用消息消费者对象 (MessageConsumer) 从指定的物理目标(在 API 中表示为目标对象)接收消息。共有两种类型的目标,分别是队列和主题,具体类型取决于消息传送模型。
消息消费者可以利用消息选择器,使消息服务只传送那些属性匹配特定选择标准的消息。
- 同步使用是指,消费者明确请求传送消息并随后使用该消息。
- 异步使用是指,自动将消息传送给为消费者注册的消息侦听器对象 (MessageListener)。当会话线程调用消息侦听器对象的 onMessage() 方法时,客户机将使用该消息。
JMS 支持两种截然不同的消息传送模型:点对点模型和发布/订阅模型。
点对点(队列目标) 消息从一个生产者传送至单个消费者。在此传送模型中,目标类型是队列。消息首先被传 送至队列目标,然后从该队列将消息传送至对此队列进行注册的某个消费者,一次只传送一条消息。可以向队列目标发送消息的生产者的数量没有限制,但每条消息 只能发送至、并由一个消费者成功使用。如果没有已经向队列目标注册的消费者,队列将保留它收到的消息,并在某个消费者对该队列进行注册时将消息传送给该消 费者。
发布/订阅(主题目标) 消息从一个生产者传送至任意数量的消费者。在此传送模型中,目标类型是主题。消息首先被传送至主题目标,然后传送至所有已订阅此主题的活动消费者。可以向主题目标发送消息的生产者的数量没有限制,并且每个消息可以发送至任意数量的订阅消费者。
主题目标也支持长期订阅。长期订阅表示消费者已注册了主题目标,但在消息到达目标时该消费者可以处于非活动状态。当消费者再次处于活动状态时,将会接收该消息。如果消费者均没有注册某个主题目标,该主题只保留注册了长期订阅的非活动消费者的消息。
这两种消息传送模型使用三组表示不同编程域的 API 对象(其语义略有不同)进行处理,如表 1-2 所示。
Destination(Queue 或 Topic)1 | ||
1取决于编程方法,您必须指定特定的目标类型。 |
JMS 版本 1.1 中引入了统一域。如果需要遵循早期的 1.02b 规范,可以使用特定于域的 API。使用特定于域的 API 还具有编程接口为全新接口的优点,可以防止出现某些类型的编程错误:例如,为队列目标创建长期订户。不过,特定于域的 API 也有缺点,即无法合并同一事务或会话中的点对点操作及发布/订阅操作。如果需要执行该操作,则应选择统一的域 API。
Message Queue 产品包含的示例应用程序以及 Message Queue 文档中提供的很多代码示例均使用单独的编程域。
可以将消息的传送模式设置为持久性或非持久性;此模式控制消息传送的可靠性。
- 保证只将持久性消息传送并成功使用一次。在消息服务发生故障时,持久性消息不会丢失。对于这些消息,可靠性是优先考虑的因素。
- 保证最多将非持久性消息传送一次。在消息服务发生故障时,非持久性消息将会丢失。对于这些消息,可靠性并非主要的考虑因素。
对于持久性消息,确保可靠性有两个方面。一方面,通过使用确认和事务来确保成功生成和使用消息。另一方面,通过将消息放在持久性存储库中,确保在将持久性消息传送至消费者之前消息服务不会丢失持久性消息。
可靠的消息传送取决于保证成功地将持久性消息从消息生产者传送到消息服务器上的物理目标,然后再成功地从该物理目标传送到消息消费者。这种可靠性可以通过 JMS 会话支持的两个通用机制实现:确认或事务。事务可以是本地事务或分布式事务(由分布式事务管理器控制)。
确认是在客户机与消息服务间发送的消息,用于确保可靠地进行传送。
生成消息时,消息服务确认它已收到传送的消息,将该消息置于其目标中并进行持久性存储。生产者的 send() 方法会阻塞,直至确认返回为止。
使用消息时,客户机确认已收到从某个目标传送来的消息并已使用,然后消息服务从该目标中删除消息。JMS 规定了不同的确认模式,它们分别代表不同的可靠性级别。在其中的某些模式下,客户机会阻塞,等待消息服务器确认已删除某个消息,并因此无法重新传送该消息。
可以将会话配置为已处理,这样,可以将一个或多个消息的生成和/或使用组成原子单元,也就是事务。JMS API 提供了启动、提交或回滚事务的方法。
在事务中生成或使用消息时,消息服务跟踪各个发送和接收 过程,并在 JMS 客户机发出提交事务的调用时完成这些操作。如果事务中特定的发送或接收操作失败,则出现异常。客户机代码通过忽略异常、重试操作或回滚整个事务来处理异 常。在事务提交时,将完成其所有操作。在事务进行回滚时,将取消所有成功的操作。
本地事务的范围始终为一个会话。也就是说,可以将单个会话的上下文中执行的一个或多个生产者或消费者操作组成一个本地事务。
由于事务的范围只能为单个的会话,因此不存在既包括消息生成又包括消息使用的端对端事务。(换句话说,至目标的消息传送和随后进行的至客户机的消息传送不能放在同一个事务中。)
JMS 规范还支持分布式事务。也就 是说,消息的生成和使用可作为较大的分布式事务的一部分,该分布式事务中包括涉及其他资源管理器(如数据库系统)的操作。在分布式事务中,分布式事务管理 器使用在 Java 事务 API (JTA)、XA 资源 API 规范中定义的两阶段提交协议跟踪和管理由多个资源管理器(如消息服务和数据库管理器)执行的操作。在 Java 中,JTA 规范说明了资源管理器和分布式事务管理器之间的交互。
支持分布式事务是指消息传送客户机可通过 JTA 定义的 XAResource 接口参与分布式事务。此接口定义了实现两阶段提交的许多方法。当客户机端进行 API 调用时,JMS 消息服务只与分布式事务管理器(由 Java 事务服务 (JTS) 提供)协作来跟踪分布式事务中的各种发送和接收操作、事务状态并完成消息传送操作。
处理本地事务时,客户机通过忽略异常、重试操作或回滚整个分布式事务来处理异常。
另一方面的可靠性就是确保在将持久性消息传送至消费者之前,消息服务不会将它们丢失。这意味着,当持久性消息到达其物理目标时,消息服务器必须将其置于持久性数据存储库中。如果消息服务器由于某种原因发生故障,它可以恢复此消息并将其传送至相应的消费者。
消息服务器还必须持久性地存储长期订阅。否则,当消息服务器发生故障时,就无法向长期订户传送消息;消息到达主题目标后,长期订户会恢复活动状态。
要保证成功传送消息,消息传送应用程序必须将消息指定为持久性消息,并将它们传送给具有长期订阅的主题目标或传送给队列目标。
JMS 编程模型中使用的两个对象(连接工厂和目标)可能会因提供者的 JMS 规范实现而有所不同。
为使提供者在定义这些对象时具有最大限度的灵活性,同时使客户机具有移植性,JMS 规范定义了受管理对象(针对连接工厂和目标),其中封装了特定于提供者的信息。这些对象由管理员创建和配置,并存储在 JNDI 名称空间(对象存储库)中,由客户机通过标准 JNDI 查找代码来访问。
受管理对象允许 JMS 客户机使用逻辑名称查找和引用特定于提供者的对象。这样,客户机代码无需知道提供者使用的特定命名语法、寻址语法或可配置属性。从而使代码与提供者无关。
受管理对象一节提供了有关 Message Queue 中使用的受管理对象的其他信息。
| |
JMS 规范并不要求您必须使用 JNDI 查找来访问受管理对象。客户机代码可以实例化连接工厂和目标对象,并设置其属性值。不过,这意味着客户机代码无法移植到其他提供者上。 | |
|