Sun Java 徽标     上一页      目录      索引      下一页     

Sun 徽标
Sun Java System Message Queue 3 2005Q4 技术概述 

第 2 章
客户端编程模型

本章介绍 Message Queue 客户端编程的基本知识,涵盖了以下主题:

本章着重介绍 Java 客户端的设计与实现。C 客户端设计与 Java 客户端设计大体上是平行的。本章的最后一节概述 Java 客户端与 C 客户端之间的差异。有关 Message Queue 客户端编程的详细论述,请参见 Message Queue Developer's Guide for Java ClientsMessage Queue Developer's Guide for C Clients

第 3 章“Message Queue 服务”说明如何使用 Message Queue 服务来支持、管理和调整消息传送性能。


设计与性能

Message Queue 应用程序的行为取决于多个因素:客户端设计、连接配置、代理配置、代理调整及资源管理。在这些因素中,一部分是开发者的责任,另外一部分则是管理员的责任。不过,最理想的情况是开发者了解 Message Queue 服务如何支持和调整应用程序设计,而管理员在调整应用程序时了解设计目标。通过重新设计以及仔细的监视和调整,可以优化消息传送性能。所以,开发出高性能 Message Queue 应用程序的关键是开发者和管理员了解应用程序生命周期各阶段可实现的目标,并交流有关预期性能及观测性能的信息。


消息传送域

消息传送中间件使各组件和应用程序可通过生成并使用消息来进行通信。JMS API 定义管理该通信的两种模式或消息传送域点对点消息传送发布/订阅消息传送。JMS API 被组织为支持以上模式。基本 JMS 对象:用于指定两个域中的消息传送行为的连接、会话、生成方、使用方、目标和消息。

点对点消息传送

在点对点域中,消息生成方被称为发送者,而使用方则被称为接收者。它们通过被称为队列的目标来交换消息:发送者生成队列中的消息;而接收者则使用队列中的消息。

图 2-1 显示了点对点域中最简单的消息传送操作。MyQueueSender 向队列目标 MyQueue1 发送 Msg1。然后,MyQueueReceiverMyQueue1 获得该消息。

图 2-1 简单点对点消息传送

消息通过队列目标从发送者传输给接收者。该图用文本进行说明。

图 2-2 显示了一个更为复杂的点对点消息传送图,以说明该域中的可能情况。两个发送者 MyQSender1MyQSender2 使用同一连接向 MyQueue1 发送消息。MyQSender3 使用另一连接向 MyQueue1 发送消息。在接收端,MyQReceiver1 使用 MyQueue1MyQReceiver2MyQReceiver3 中的消息,共享一个连接以使用 MyQueue1 中的消息。

图 2-2 复杂点对点消息传送

图中显示了使用一个连接向一个接收者发送消息的两个发送者。还显示了从同一队列获得消息的两个使用者。该图用文本进行说明。

该图略为复杂,说明了有关点对点消息传送的其他几点。

点对点模型具有许多优势:

发布/订阅消息传送

在发布/订阅域中,消息生成方被称为发布者,而消息使用方则被称为订户。它们通过称为主题的目标来交换消息:发布者生成主题中的消息;订户则订阅主题并使用主题中的消息。

图 2-3 显示了发布/订阅域中的简单消息传送操作。MyTopicPublisher 向目标 MyTopic 中发布 Msg1。然后,MyTopicSubscriber1MyTopicSubscriber2 均从 MyTopic 接收 Msg1 的副本。

图 2-3 简单发布/订阅消息传送

图中显示了通过一个主题目标向两个订户发送同一条消息的一个发布者。该图用文本进行说明。

虽然发布/订阅模型不需要存在多个订户,但图中显示了两个订户,这是为了强调在该域中可以广播消息。一个主题的所有订户均可获得发布到该主题的任何消息的副本。

订户可以是非长期的,也可以是长期的。代理会为所有活动订户保留消息,但对于非活动订户,则只为那些长期订户保留消息。

图 2-4 显示了更为复杂的发布/订阅消息传送图,以说明该模式提供的可能情况。多个生成方向 Topic1 目标发布消息。多个订户使用来自 Topic1 目标的消息。除非订户使用选择器来过滤消息,否则每个订户均可获得发布到所选主题的所有消息。在图 2-4 中,MyTSubscriber2 已过滤掉 Msg2

图 2-4 复杂发布/订阅消息传送

图中显示了通过一个主题目标向三个订户发送消息的三个发布者。该图用文本进行说明。

该图略为复杂,说明了有关发布/订阅消息传送的其他几点。

发布/订阅模型的主要优势在于它允许向订户广播消息。

特定于域的 API 及统一域 API

JMS API 定义可用于实现点对点域或发布/订阅域的接口和类。这些是表 2-1 的第 2 列和第 3 列中显示的特定于域的 API。JMS API 还定义另外一个统一域,用于通过编程实现常规的消息传送客户端。这类客户端的行为由目标类型决定,客户端向目标中生成消息并使用目标中的消息。如果该目标是一个队列,则消息传送行为将为点对点模式;如果该目标是一个主题,则消息传送行为将为发布/订阅模式。

表 2-1 JMS 编程域和对象 

基本类型(统一域)

点对点域

发布/订阅域

Destination(Queue 或 Topic)1

Queue

Topic

ConnectionFactory

QueueConnectionFactory

TopicConnectionFactory

Connection

QueueConnection

TopicConnection

Session

QueueSession

TopicSession

MessageProducer

QueueSender

TopicPublisher

MessageConsumer

QueueReceiver

TopicSubscriber

1 根据编程方法,您必须指定特定的目标类型。

JMS 版本 1.1 中引入了统一域。如果需要遵循早期的 1.02b 规范,可以使用特定于域的 API。使用特定于域的 API 还能够提供全新编程接口,可以防止出现某些类型的编程错误:例如,为队列目标创建长期订户。不过,特定于域的 API 也有缺点,即无法合并同一事务或会话中的点对点操作及发布/订阅操作。如果需要执行该操作,则应选择统一域 API。有关组合两种域的示例,请参见请求-回复模式


编程对象

用于实现 JMS 消息传送的对象在编程域中基本保持不变:连接工厂、连接、会话、生成方、使用方、消息和目标。这些对象显示在图 2-5 中。图中从连接工厂对象开始,自上而下地显示对象是如何派生出来的。

显示的连接工厂和目标这两类对象驻留在对象存储中。这是为了强调通常将这些对象作为受管理对象来创建、配置和管理。我们假定本章中的连接工厂和目标都是以管理方式(而不是以编程方式)创建的。

图 2-5 JMS 编程对象

图中显示了连接工厂、连接、会话、生成方、使用方、消息以及目标之间的关系。该图用文本进行说明。

表 2-2 概述了发送和接收消息所需的步骤。请注意,步骤 1 以及步骤 3 到 6 对于发送者和接收者来说是相同的。

表 2-2 生成和使用消息

生成消息

使用消息

1. 管理员创建连接工厂受管理对象。

2. 管理员创建物理目标以及引用该目标的受管理对象。

3. 客户端通过 JNDI 查找获得连接工厂对象。

4. 客户端通过 JNDI 查找获得目标对象。

5. 客户端创建连接并设置特定于该连接的所有属性。

6. 客户端创建会话并设置决定消息传送可靠性的属性。

7. 客户端创建消息生成方。

客户端创建消息使用方。

8. 客户端创建消息。

客户端建立连接。

9. 客户端发送消息。

客户端接收消息。

以下几节将介绍生成方和使用方使用的对象:连接、会话、消息和目标。之后,我们将通过说明消息的生成和使用来完成对 JMS 对象的介绍。

连接工厂和连接

客户端使用 connection factory(连接工厂)对象 (ConnectionFactory) 来创建 connection(连接)。连接对象 (Connection) 表示客户端与代理之间的活动连接。它使用在默认情况下启动或者由管理员为该客户端明确启动的底层连接服务。

创建连接时,将分配通信资源并验证客户端。这是一个相当重要的对象,大多数客户端均使用一个连接来完成所有的消息传送。连接支持并发使用:一个连接可由任意数量的生成方和使用方共享。

创建连接工厂时,可通过设置它的属性来配置从它派生的所有连接的行为。对于 Message Queue,这些设置可指定以下信息:

可以在用于启动客户端应用程序的命令行上覆盖连接工厂属性。还可以通过设置任意给定连接的属性来覆盖该连接的属性。

可使用连接对象来创建 session(会话)对象,从而设置异常侦听器或者获得 JMS 版本及提供者信息。

会话

如果连接代表客户端与代理之间的通信渠道,则会话标记客户端与代理之间的单次对话。会话对象主要用于创建消息、消息生成方和消息使用方。创建会话时,通过多个 acknowledgement(确认)选项或通过事务来配置可靠传送。有关详细信息,请参见可靠消息传送

从 JMS 规范可看出,会话是生成和使用消息的单线程上下文。可以为一个会话创建多个消息生成方和使用方,但只能顺次使用它们。Java 客户端与 C 客户端在线程实现上的差异非常小。有关线程实现与限制的其他信息,请参考相应的开发者指南。

还可以使用会话对象来完成以下任务:

消息

消息由三部分组成:消息头、属性和主体。您必须了解此结构,才能正确编写消息和配置某些消息传送行为。

消息头

每条 JMS 消息都必须有消息头。消息头包含十个预定义字段,表 2-3 中列出并介绍了这些字段。

表 2-3 JMS 定义的消息头 

头字段

描述

JMSDestination

指定消息要发送到的目标对象的名称。(由提供者设置。)

JMSDeliveryMode

指定消息是否为持久性消息。(默认情况下由提供者设置,也可以由客户端为生成方或为单独的消息显式设置。)

JMSExpiration

指定消息的到期时间。(默认情况下由提供者设置,也可以由客户端为生成方或为单独的消息设置。)

JMSPriority

指定消息的优先级,范围为 0(低)到 9(高)。(默认情况下由提供者设置,也可以由客户端为生成方或为单独的消息显式设置。)

JMSMessageID

指定消息在提供者安装的上下文中的唯一 ID。(由提供者设置。)

JMSTimestamp

指定提供者接收消息的时间。(由提供者设置。)

JMSCorrelationID

客户端用于定义两条消息之间的对应性的值。(由客户端在需要时设置。)

JMSReplyTo

指定使用方应发送回复的目标。(由客户端在需要时设置。)

JMSType

可由消息选择器评估的值。(由客户端在需要时设置。)

JMSRedelivered

指定消息是否已传送但尚未得到确认。(由提供者设置。)

通读上表可知,消息头字段可用于多种用途:标识消息,配置消息路由,提供有关消息处理的信息等等。

JMSDeliveryMode 是最重要的字段之一,它决定了消息传送的可靠性。该字段指示一条消息是否为持久性消息。

部分消息头字段由提供者(代理或客户端运行时)设置,其他头字段则由客户端设置。消息生成方可能需要配置头字段值,才能实现某些消息传送行为;消息使用方可能需要读取头字段值,才能了解消息的路由方式以及可能需要对它执行哪些进一步处理。

可以在三个不同级别设置头字段(JMSDeliveryMode、JMSExpiration 和 JMSPriority):

如果这些字段是在多个级别设置的,则为连接工厂设置的值会覆盖为单独的消息设置的那些值;而为给定消息设置的值会覆盖为消息生成方设置的那些值。

消息头字段的固定名称因语言实现而异。有关详细信息,请参见 Message Queue Developer's Guide for Java ClientsMessage Queue Developer's Guide for C Clients

消息属性

消息还可以包含称为属性的可选头字段,这类字段以属性名/属性值对的形式来指定。客户端和提供者可以使用属性来扩展消息头,并可以在其中包含有助于客户端或提供者标识和处理消息的任何信息。利用消息属性,接收客户端可以要求仅传送符合给定标准的那些消息。例如,使用方客户端可能请求获得有关新泽西州兼职雇员工资单的消息。提供者将不会传送不符合指定标准的消息。

JMS 规范定义九个标准属性。其中部分由客户端设置,部分由提供者设置。这些属性的名称以保留字符 "JMSX" 开头。客户端或提供者可以使用这些属性来确定消息发送者、消息的状态以及传送的频率和时间。这些属性有助于提供者提供路由消息和诊断信息。

Message Queue 也定义消息属性,它们用于标识压缩消息以及在无法传送消息时应如何处理消息。有关详细信息,请参见 Message Queue Developer's Guide for Java Clients

消息主体

消息主体包含客户端需要交换的数据。

JMS 消息类型决定了主体可以包含哪些内容以及使用方应如何处理主体,如表 2-4 中所指定的那样。Session 对象包含各类消息主体的创建方法。

表 2-4 消息主体类型 

类型

描述

StreamMessage

主体中包含 Java 基元值流的消息。它的填充和读取均按顺序进行。

MapMessage

主体中包含一组名/值对的消息。没有定义条目顺序。

TextMessage

主体中包含 Java 字符串的消息,例如 XML 消息。

ObjectMessage

主体中包含序列化 Java 对象的消息。

BytesMessage

主体中包含连续字节流的消息。

Java 客户端可设置相应的属性,以使客户端运行时压缩发送的消息的主体。使用方一端的 Message Queue 运行时会在传送消息前先解压缩消息。


生成消息

消息由消息生成方在连接和会话的上下文中发送或发布。生成消息相当简单:客户端使用消息生成方对象 (MessageProducer) 向物理 destination(目标)(在 API 中由目标对象表示)发送消息。

创建生成方时,可指定生成方的所有消息将发送到的默认目标。您也可以指定决定持久性、优先级和有效期的消息头字段的默认值。这样,从该生成方发出的所有消息都使用这些默认值,除非您通过在发送消息时指定替代目标,或者为给定消息的头字段设置替代值来覆盖它们。

消息生成方也可以通过设置 JMSReplyTo 消息头字段来实现请求-回复模式。有关详细信息,请参见请求-回复模式


使用消息

消息由消息使用方在连接和会话的上下文中接收。客户端使用消息使用方对象 (MessageConsumer) 从指定的物理目标(在 API 中由目标对象表示)接收消息。

三个因素影响代理向使用方传送消息的方式:

影响消息传送和客户端设计的另一主要因素是使用方需要的可靠度。请参见可靠消息传送

同步和异步使用方

消息使用方可以支持同步或异步消息使用。

使用选择器过滤消息

消息使用方可以利用消息选择器,使消息服务只传送那些属性匹配特定选择标准的消息。该标准在创建使用方时指定。

选择器使用类似 SQL 的语法来匹配消息属性。例如,

color = 'red'

size > 10

Java 客户端也可以在浏览队列时指定选择器;这样您可以查看在所选消息中,哪些消息正在等待被使用。

使用长期订户

可以使用会话对象创建主题的长期订户。即使订户变为非活动状态,代理也会为这些类型的订户保留消息。

由于代理必须维护订户的状态并在订户被重新激活后恢复消息传送,因此,代理必须能够在给定订户的订阅期内识别该订户。订户标识是根据创建该订户的连接的 ClientID 属性以及创建订户时指定的订户名构造的。


请求-回复模式

可以在一个连接中同时包含生成方和使用方(在使用统一 API 时甚至可包含会话)。此外,JMS API 允许使用临时目标来实现消息传送操作的请求-回复模式。

消息生成方必须执行以下操作才能设置请求-回复模式:

  1. 创建使用方可发送回复的临时目标。
  2. 在要发送的消息中,将消息头的 JMSReplyTo 字段设置为该临时目标。

消息使用方在处理消息时,会检查消息的 JMSReplyTo 字段,以确定是否需要回复并向指定目标发送回复。

如果采用请求-回复机制,生成方将无需为回复目标设置受管理对象,并且使用方可以轻松地响应请求。当生成方只有在确保请求已处理后才能继续时,此模式非常有用。

图 2-6 说明了向主题中发送消息并接收临时队列中的回复的请求/回复模式。

图 2-6 请求/回复模式

图中显示了通过一个主题目标向两个订户发送消息、通过一个队列目标接收回复的发布者。该图用文本进行说明。

如图所示,MyTopicPublisher 生成 Msg1 并将它发送到目标 MyTopicMyTopicSubsriber1MyTopicSubscriber2 接收该消息并向 MyTempQueue 发送回复,MyTQReceiver 从 MyTempQueue 中检索该回复。该模式可能适用于向大量客户端发布定价信息,并将客户端的回复订单排队以便按顺序进行处理的应用程序。

临时目标的存在时间只能与创建它们的连接的存在时间一样长。任何生成方都可以向临时目标发送消息,但只有创建目标的连接所创建的那些使用方能够访问临时目标。

由于请求/回复模式依赖于创建临时目标,因此在以下情况下不应使用该模式:


可靠消息传送

消息传送在两个跃点上进行:第一个跃点从代理上的物理目标的生成方获得消息;第二个跃点从使用方的目标获得消息。因此,在下面的三个阶段,消息可能丢失:在至代理的跃点上,当代理发生故障时在代理内存中以及在代理至使用方的跃点上。可靠传送可保证传送过程在上述任一阶段都不会失败。由于当代理失败时非持久性消息总是会丢失,因此可靠传送仅适用于持久性消息。

使用了两种机制来确保可靠传送:

以下各节将介绍这两个方面的可靠性保证措施。

确认

确认是指客户端与消息服务之间为确保可靠消息传送而发送的消息。对于生成方和使用方,确认的用途是不同的。

生成消息时,代理确认它已收到消息,将该消息放入它的目标中并永久存储它。生成方的 send() 方法会被阻止,直至它收到此确认为止。这些确认对于持久性消息要发送到的客户端是透明的。

使用消息时,客户端确认已收到从某个目标传送来的消息并已使用它,然后代理从该目标中删除该消息。JMS 规定了不同的确认模式,它们分别代表不同的可靠度。

对于更关心性能而不是可靠性的客户端,Message Queue 服务通过提供 NO_ACKNOWLEDGE 模式来扩展 JMS API。在该模式下,代理不跟踪客户端确认,所以不保证使用方客户端已成功处理了消息。对于发送至非长期订户的非持久性消息,选择该模式可提高性能。

事务

事务是将一条或多条消息的生成和/或使用组合到一个工作单位的方法。上述客户端和代理确认过程同样适用于事务。在这种情况下,客户端运行时和代理确认默认在事务级别进行。当事务提交时,将自动发送代理确认。

可以将会话配置为事务,并且 JMS API 提供了启动、提交和回滚事务的方法。

在事务中生成或使用消息时,消息服务跟踪各个发送和接收过程,并只有在 JMS 客户端发出提交事务的调用时才完成这些操作。如果事务中特定的发送或接收操作失败,将引发异常。客户端代码可以通过忽略异常、重试操作或回滚整个事务来处理异常。事务提交时,所有操作都已完成。事务回滚时,所有成功的操作都取消。

事务的作用范围始终为一个会话。也就是说,可以将在单个会话的上下文中执行的一个或多个生成方或使用方操作组成一个事务。由于事务只能跨越单个会话,因此不存在既包括消息生成又包括消息使用的端对端事务。

JMS 规范还支持分布式事务。也就是说,消息的生成和使用可以是大型分布式事务的一部分,该事务中包括涉及其他资源管理器(如数据库系统)的操作。必须有事务管理器(例如,Java Systems Application Server 提供的事务管理器)才能支持分布式事务。

在分布式事务中,分布式事务管理器使用在 Java 事务 API (Java Transaction API, JTA) XA 资源 API 规范中定义的两阶段提交协议,来跟踪和管理由多个资源管理器(如消息服务和数据库管理器)执行的操作。在 Java 中,资源管理器与分布式事务管理器之间的交互在 JTA 规范中描述。

支持分布式事务是指消息传送客户端可通过 JTA 定义的 XAResource 接口参与分布式事务。此接口定义了实现两阶段提交的许多方法。当客户端进行 API 调用时,JMS 消息服务只与分布式事务管理器(由 Java 事务服务 (Java Transaction Service, JTS) 提供)协作来跟踪分布式事务中的各种发送和接收操作、跟踪事务状态并完成消息传送操作。

与本地事务一样,客户端可以通过忽略异常、重试操作或回滚整个分布式事务来处理异常。

持久性存储器

另一方面的可靠性就是确保在将持久性消息传送至使用方之前,代理不会将它们丢失。这意味着,当消息到达物理目标时,代理必须将消息放入持久性 data store(数据存储)中。如果代理由于某种原因发生故障,它可以在以后恢复此消息并将此消息传送至相应的使用方。

此外,代理必须永久存储长期订阅。否则,当代理发生故障时,就无法向长期订户传送消息;当有消息到达主题目标后,长期订户就会变为活动状态。

要保证成功传送消息,消息传送应用程序必须将消息指定为持久性消息,并将它们传送给具有长期订阅的主题目标或传送给队列目标。

第 3 章“Message Queue 服务”介绍了 Message Queue 服务提供的默认消息存储,以及管理员如何设置和配置替代的存储。


消息在系统中的传送路线

作为对上述内容的总结,本节介绍如何使用 Message Queue 服务从生成方向使用方传送消息。为了描绘一个完整的画面,我们需要补充另外一个细节:在传送过程中,系统处理的消息分为以下两类:

图 2-7 说明了消息传送过程。

图 2-7 消息传送步骤

该图显示在消息传送过程中,以持久、可靠的方式传送消息的步骤。该图用文本进行说明。

以持久、可靠的方式传送消息的步骤如下:

消息生成

1.   客户端运行时通过连接将消息从消息生成方传送到代理。

消息处理和路由

2.   代理从连接中读取消息并将此消息放入相应的目标中。

3.   代理将(持久性)消息放入数据存储中。

4.   代理向消息生成方的客户端运行时确认已收到消息。

5.   代理确定消息的路由。

6.   代理将消息从目标写入适当的连接,并使用使用方的唯一标识符标记该消息。

消息使用

7.   消息使用方的客户端运行时将消息从连接传送到消息使用方。

8.   消息使用方的客户端运行时向代理确认消息已使用。

消息生命周期结束

9.   代理处理客户端确认,并在收到所有确认后删除(持久性)消息。

10.   代理向使用方的客户端运行时确认,告知客户端确认已得到处理。


使用 SOAP 消息

使用 SOAP(请参见对 Java 客户端的 SOAP 支持)可以在分布式环境中的两个对等方之间交换结构化数据(由 XML 方案指定)。SOAP 的 Sun 实现当前不支持可靠 SOAP 消息传送,也不支持发布 SOAP 消息。不过,您可以使用 Message Queue 服务获得可靠的 SOAP 消息传送,并在需要时发布 SOAP 消息。Message Queue 服务并不直接传送 SOAP 消息,但它允许您将 SOAP 消息包装为 JMS 消息并像生成和使用正常的 JMS 消息一样生成和使用这些消息,然后从 JMS 消息中提取 SOAP 消息。

Message Queue 通过两个软件包来提供 SOAP 支持:javax.xml.messagingcom.sun.messaging.xml。您可以使用在这些库中实现的类来接收 SOAP 消息,将 SOAP 消息包装为 JMS 消息,然后从 JMS 消息中提取 SOAP 消息。J2EE 平台提供软件包 java.xml.soap,您可以使用它来组合和分解 SOAP 消息。

要实现可靠的 SOAP 消息传送,需要执行以下操作:

  1. 使用 java.xml.soap 软件包中定义的对象构造 SOAP 消息,或使用 javax.xml.messaging 软件包中定义的 servlet 接收 SOAP 消息,也可以使用 JAX-RPC 等 Web 服务来接收 SOAP 消息。
  2. 使用 MessageTransformer 实用程序将 SOAP 消息转换为 JMS 消息。
  3. 将 JMS 消息发送到所需目标。
  4. 以异步方式或同步方式使用 JMS 消息。
  5. 在 JMS 消息已使用后,使用 MessageTransformer 实用程序将它转换为 SOAP 消息。
  6. 使用 SAAJ API(在 java.xml.soap 软件包中定义)分解 SOAP 消息。

有关 SOAP 消息及其处理的详细信息,请参见 Message Queue Developer's Guide for Java Clients


Java 客户端与 C 客户端

Message Queue 向消息传送服务提供 C API,使传统 C 应用程序和 C++ 应用程序可参与基于 JMS 的消息传送。

JMS 编程模型是设计 Message Queue C 客户端的基础。Message Queue Developer's Guide for C Clients 说明了 C 数据类型及函数如何实现该模型。

与 Java 接口一样,C 接口也支持以下功能:

不过,必须了解 Java Message Service 规范是仅适用于 Java 客户端的标准;所以,C Message Queue API 特定于 Message Queue 提供者,不能用于其他 JMS 提供者。包含 C 客户端的消息传送应用程序不能由另一 JMS 提供者处理。

C 接口不支持以下功能:



上一页      目录      索引      下一页     


文件号码:819-3565。  版权所有 © 2005 Sun Microsystems, Inc. 保留所有权利。