1、 JMS1.1规范 中文版 卫建军 20071122 2 / 66 译者序 Java是当前IT领域中比较流行的技术之一。J2EE是当前比较流行的企业级应用架构。本人一直致力于J2EE架构的学习和研究,但是总是对英文文档有不可言语的恐惧。我想很多J2EE爱好者和我有同样的感觉。这样就影响了我们深入学习J2EE原始规范的兴趣。但是J2EE原始的规范文档对我们深入理解J2EE有很大的帮助,因为它阐述了规范的来龙去脉,以及违反了规范会造成什么样的影响。了解了这些缘由和影响,会使我们对J2EE架构有更深层次的理解。这也是我翻译该规范的动力所在。 由于本人的英语水平有限,翻译中难免会出现错误和拗口之处,请
2、大家多多指教。 这次主要翻译的规范有EJB3规范简化版、J2EE5.0规范、EJB核心规范、EJB3持久化规范和JMS1.1规范。希望对大家有所帮助。 卫建军 200815于北京 3 / 66 目录 目录 3 1 引言. 8 1.1 摘要 . 8 1.2 概述 . 8 1.2.1 是Mail API吗? . 8 1.2.2 现存的消息系统 . 8 1.2.3 JMS目标 . 9 1.2.4 JMS不包含什么 . 10 1.3 JMS的要求是什么 . 10 1.4 与其他Java API的关系 10 1.4.1 JDBC软件 10 1.4.2 JavaBean组件 . 10 1.4.3 EJB组
3、件模型 11 1.4.4 Java事务API(JTA) . 11 1.4.5 Java事务服务(JTS) 11 1.4.6 Java命名和目录接口API(JNDI) . 11 1.4.7 J2EE平台 11 1.4.8 JMS和EJB组件的集成 12 1.5 JMS1.1的新特性是什么? 12 2 架构. 12 2.1 概述 . 12 2.2 什么是JMS应用 12 2.3 管理 . 13 2.4 两种消息风格 . 13 2.5 JMS接口 . 14 2.6 开发一个JMS应用 15 2.6.1 开发一个JMS客户端 15 2.7 安全 . 15 2.8 多线程 . 15 2.9 触发式客户端
4、 . 16 2.10 请求/回复 . 16 3 JMS消息模型 . 16 3.1 背景 . 16 3.2 目标 . 17 3.3 JMS消息 . 17 3.4 消息头字段 . 17 3.4.1 JMSDestination 17 3.4.2 JMSDeliveryMode . 17 3.4.3 JMSMessageID 18 3.4.4 JMSTimestamp 18 3.4.5 JMSCorrelationID. 18 3.4.6 JMSReplyTo 19 4 / 66 3.4.7 JMSRedelivered . 19 3.4.8 JMSType. 19 3.4.9 JMSExpirat
5、ion 19 3.4.10 JMSPriority 20 3.4.11 如何设置消息头的值 . 20 3.4.12 重载消息头字段 . 20 3.5 消息属性 . 20 3.5.1 属性名 . 21 3.5.2 属性值 . 21 3.5.3 属性的使用 . 21 3.5.4 属性值转换 . 21 3.5.5 属性值作为对象 . 22 3.5.6 属性迭代 . 22 3.5.7 清除消息属性的值 . 22 3.5.8 不存在的属性 . 22 3.5.9 JMS定义的属性 . 22 3.5.10 提供商专有的属性 . 23 3.6 消息确认 . 24 3.7 Message接口 . 24 3.8
6、消息选择 . 24 3.8.1 消息选择器 . 24 3.9 访问已发送的消息 . 27 3.10 改变收到的消息的值 . 28 3.11 JMS消息体 . 28 3.11.1 清除消息体 . 28 3.11.2 只读消息体 . 28 3.11.3 由StreamMessage和MapMessage提供的转换 . 29 3.11.4 用于非JMS客户端的消息 29 3.12 JMS Message接口的提供商实现 30 4 JMS公共工具 . 30 4.1 概述 . 30 4.2 受管理的对象 . 30 4.2.1 Destination 31 4.2.2 ConnectionFactory
7、31 4.3 Connection 31 4.3.1 授权 . 32 4.3.2 客户端标识 . 32 4.3.3 Connection设置 . 32 4.3.4 中止消息的转发 . 33 4.3.5 关闭Connection . 33 4.3.6 会话(Session) 34 4.3.7 ConnectionMetaData 34 4.3.8 ExceptionListener 34 4.4 Session. 34 5 / 66 4.4.1 关闭会话 . 35 4.4.2 创建MessageProducer和MessageConsumer 35 4.4.3 创建临时目的地 . 35 4.4.
8、4 创建目的地对象 . 35 4.4.5 优化消息实现 . 36 4.4.6 使用会话的约定 . 36 4.4.7 事务 . 37 4.4.8 分布式事务 . 37 4.4.9 多会话 . 37 4.4.10 消息排序 . 37 4.4.11 消息确认 . 38 4.4.12 消息的重复转发 . 39 4.4.13 消息的重复产生 . 39 4.4.14 客户端代码的有序执行 . 39 4.4.15 并行消息转发 . 39 4.5 MessageConsumer 39 4.5.1 同步转发 . 40 4.5.2 异步转发 . 40 4.6 MessageProducer 40 4.7 消息转发
9、模式 . 41 4.8 消息的生存时间 . 41 4.9 异常 . 41 4.10 可靠性 . 41 4.11 方法跨消息域继承 . 42 5 JMS点对点模型 . 42 5.1 概述 . 42 5.2 队列管理 . 43 5.3 Queue 43 5.4 TemporaryQueue 43 5.5 QueueConnectionFactory . 43 5.6 QueueConnection . 44 5.7 QueueSession 44 5.8 QueueReceiver 44 5.9 QueueBrowser 44 5.10 QueueRequestor . 44 5.11 可靠性 .
10、 45 6 JMS 发布/订阅模型 . 45 6.1 概述 . 45 6.2 Pub/Sub延时 45 6.3 永久订阅 . 46 6.4 主题(Topic)管理 46 6.5 Topic 46 6.6 TemporaryTopic . 46 6.7 TopicConnectionFactory 47 6 / 66 6.8 TopicConnection 47 6.9 TopicSession 47 6.10 TopicPublisher . 47 6.11 TopicSubscriber . 47 6.11.1 永久TopicSubscriber 48 6.12 恢复和重发 . 48 6.1
11、3 管理订阅 . 48 6.14 TopicRequestor 48 6.15 可靠性 . 48 7 JMS异常 . 49 7.1 概述 . 49 7.2 JMSException 49 7.3 标准异常 . 49 8 JMS应用服务器工具 . 50 8.1 概述 . 50 8.2 并发处理订阅的消息 . 51 8.2.1 Session . 51 8.2.2 ServerSession 51 8.2.3 ServerSessionPool . 51 8.2.4 ConnectionConsumer 52 8.2.5 ConnectionConsumer如何使用ServerSession .
12、52 8.2.6 应用服务器如何实现ServerSession . 52 8.2.7 结果 . 52 8.3 XAConnectionFactory 54 8.4 XAConnection 54 8.5 XASession 54 8.6 JMS应用服务器接口 . 54 9 JMS样例代码 . 55 9.1 准备发送和接收消息 . 55 9.1.1 获取ConnectionFactory . 55 9.1.2 获取Destination . 56 9.1.3 创建Connection . 56 9.1.4 创建Session 56 9.1.5 创建MessageProducer . 56 9.1
13、.6 创建MessageConsumer . 56 9.1.7 启动消息转发 . 57 9.1.8 使用TextMessage . 57 9.2 发送和接收消息 . 57 9.2.1 发送消息 . 57 9.2.2 同步接收消息 . 58 9.2.3 解包TextMessage . 58 9.3 其他消息特性 . 58 9.3.1 异步接收消息 . 58 9.3.2 使用消息选择器 . 59 7 / 66 9.3.3 使用永久订阅 . 59 9.4 JMS消息类型 . 61 9.4.1 创建TextMessage . 61 9.4.2 解包TextMessage . 61 9.4.3 创建By
14、tesMessage . 61 9.4.4 解包BytesMessage . 61 9.4.5 创建MapMessage 62 9.4.6 解包MapMessage 62 9.4.7 创建StreamMessage 63 9.4.8 解包StreamMessage 63 9.4.9 创建ObjectMessage . 64 9.4.10 解包ObjectMessage . 64 10 问题 . 65 10.1 已解决的问题 . 65 10.1.1 JDK1.1.x兼容性 65 10.1.2 分布式Java事件模型 65 10.1.3 可以合并JMS的两个域PTP和Pub/Sub吗? . 65
15、10.1.4 JMS应当指定一个JMS JavaBean集合吗? . 65 10.1.5 与CORBA通知服务对齐 . 65 10.1.6 JMS应当提供端对端的同步消息转发和转发通知吗? 66 10.1.7 JMS应当提供发送到列表的机制吗? . 66 10.1.8 JMS应当提供订阅通知吗? . 66 11 变更历史 . 66 8 / 66 1 引言 1.1 摘要 本规范描述了JMS的目标和功能。 JMS给java程序员提供了一种通用的方式来创建、发送、接收和查看企业消息系统消息。 1.2 概述 企业消息产品(或者有时称为面向消息的中间件产品)正逐渐成为公司内操作集成的关键组件。这些产品可
16、以将分离的业务组件组合成一个可靠灵活的系统。 除了传统的MOM供应商,企业消息产品也可以由数据库供应商和许多与网络相关的公司来提供。 Java语言的客户端和Java语言的中间层服务必须能够使用这些消息系统。JMS为Java语言程序提供了一个通用的方式来获取这些系统。 JMS是一个接口和相关语义的集合,那些语义定义了JMS客户端如何获取企业消息产品的功能。 由于消息是点对点的,所以JMS的所有用户都称为客户端(clients)。JMS应用由定义消息的应用和一系列与他们交互的客户端组成。 1.2.1 是Mail API吗? 术语“消息”在计算机领域到处都有。它用于描述各种操作系统概念;用于描述邮件
17、和传真系统;但在这里用于描述企业应用间的异步通讯。 这里描述的消息是由企业应用而不是人来处理的异步请求、报告或事件。他们包含了协同这些应用所必需的信息。他们包含了描述特定业务动作的格式化的数据。应用通过交换消息来跟踪企业的过程。 1.2.2 现存的消息系统 消息系统是点对点的工具。通常情况下,每个客户端可以发送消息到另一个客户端,也可以从任何客户端接收消息。每个客户端连接到提供创建、发送和接受消息的消息代理。 每个系统都提供了定位消息的方式。每个系统都提供了创建消息并给他填充数据的途径。 有些系统可以想多个目的地广播消息。其他的系统也可以只支持向一个目的地发送消息。 某些系统提供了异步接收消息
18、的功能(当消息到达时被转发到客户端)。其他的系统可以支持同步接收(客户端必须请求每个消息)。 每个消息系统通常提供多种服务供不同的消息来选择。重要的问题是系统能保证转发的长度是多少。它们可能不是一次就能转发完全的。其他重要的问题是消息是有时效、有优先级和是否要求响应。 9 / 66 1.2.3 JMS目标 如果JMS提供了现有消息系统的所有特性,那么对用户来讲它就太复杂了。在另一个方面,JMS更多是所有消息产品公共特性的交集。重要的是JMS要包含实现专业企业应用需要的功能。 JMS定义了一系列通用的企业消息概念和工具。它试图最小化Java语言程序员使用企业消息产品而必须了解的概念集。它致力于最
19、大化消息应用的可移植性。 1.2.3.1 JMS提供商 正如前面提到的,JMS提供商是一个在消息产品实现JMS的实体。 理想情况下,JMS提供商用纯Java来实现消息产品,这样它就能运行在applet中,简化安装,并且可以架构和OS工作。 JMS的一个重要目标是最小化实现一个提供商所需要的工作。 1.2.3.2 JMS消息 JMS定义了一系列消息接口。 客户端使用由JMS提供商提供的消息实现。 JMS的一个主要目标是客户端使用统一的API来创建和与独立于JMS提供商的消息一起工作。 1.2.3.3 JMS域 消息产品可以广义上可以分为点对点或发布订阅系统。 点对点(PTP)产品围绕着消息队列创
20、建。每个消息被放置在一个特定的队列中;客户端从队列中取出消息。 发布和订阅(Pub/Sub)客户端将消息放置到某个内容继承层次上的节点上。发布者和订阅者通常都是匿名的,通常可以动态的发布或订阅内容层级。系统关注将来自一个节点的多个发布者的消息分发到这个节点的多个订阅者。 JMS提供了一系列的接口来让客户端在两种域下发送和接收消息,同时支持每个域的语义。JMS也为每个域提供了相应的客户端接口。JMS1.1规范以前的版本,只有对应于每个域的客户端接口。这些接口继续被支持以提高向后的兼容性。实现客户端的最好方式是使用不依赖域的接口。这些接口称为“通用接口”是域特有接口的父类。 1.2.3.4 可移植
21、性 最主要的可移植目标是新的只有JMS的应用可以在同一个消息域内可以跨产品。 另外,JMS客户端跨机器架构和操作系统是期望的可移植性(当时有同一个JMS提供商时)。 10 / 66 尽管设计JMS的目的是让客户端可以和现存的在混合语言应用中使用的消息格式一起工作,但是这种客户端通常是不可移植的(将一个混合语言应用从一个产品移植到另一个产品超出了JMS的范围)。 1.2.4 JMS不包含什么 JMS没有包含下列功能: z 负载均衡/容错(Load Balancing/Fault Tolerance)许多产品为对多个协同的客户端提供了关键的服务。JMS API没有指定这种客户端协同如何作为一个单独
22、的统一的服务出现。 z 错误/劝告通知(Error/Advisory Notification)多数消息产品定义系统消息来向客户端提供问题或系统事件的异步通知。JMS没有试图标准化这些消息。通过遵循由JMS定义的指南,客户端可以避开这些消息,这样就可以防止由于使用这些消息而引入的可移植性问题。 z 管理JMS没有定义管理消息产品的API。 z 安全JMS没有定义用于控制消息私密性和完整性的API。它也没有指定数字签名或密钥如何被分发到客户端。安全是由JMS提供商要考虑的问题由管理员配置这些特有的特性,而不是由客户端使用JMS API来控制。 z 通讯协议(Wire Protocal)JMS没有
23、定义消息的通讯协议。 z 消息类型存储池JMS没有定义存储消息类型定义的存储池,也没有定义创建消息类型定义的语言。 1.3 JMS的要求是什么 在这个规范内讨论的功能都是对JMS提供商的要求,除非它被显式的指出。 JMS点对点功能的提供商不要求提供发布/订阅功能,反之亦然。 JMS也可以用在J2EE平台。参加章节1.4 ,“与其他Java API的关系”来了解当JMS被集成到那种软件环境时对JMS的附加要求。 1.4 与其他Java API的关系 1.4.1 JDBC软件 JMS客户端也可以使用JDBC API。他们可能希望在同一个事务内使用JDBC API和JMS API。大多数情况下,通过
24、将这些客户端实现为EJB组件可以自动实现这个愿望。也可能直接使用JTA来实现这个愿望。 1.4.2 JavaBean组件 JavaBean组件可以使用JMS会话来发送/接收消息。JMS本身是一个API,它定义的接口没有打算直接作为JavaBean组件来使用。 11 / 66 1.4.3 EJB组件模型 JMS API是EJB组件开发者可以获得的重要资源。它可以和类似JDBC的资源一起使用来实现企业服务。 EJB2.0规范定义了通过来自EJB客户端调用的方法被同步调用的bean。也定义了一种异步bean,当一个JMS客户端向他发送消息时它被调用,称为消息驱动bean。EJB规范支持同步和异步消息
25、消费。另外,EJB2.0指定JMS API如何参与bean管理的或容器管理的事务。EJB2.0规范限制了当实现EJB客户端时如何使用JMS接口。参考EJB2.0规范来了解更详细的内容。 1.4.4 Java事务API(JTA) Javax.transaction包为划分分布式事务提供了客户端API,并提供了获取要参与到分布式事务中的资源的API。 JMS客户端可以使用JTA来划分分布式事务;但是,这是运行客户端的事务环境的功能。不是JMS的功能。 JMS提供商可以通过JTA支持分布式事务,也可以不支持。 1.4.5 Java事务服务(JTS) JMS可以和JTS联合使用来组成分布式事务,这个分
26、布式事务将消息的发送和接收与数据更新及其他JTS感知的服务结合起来。当JMS客户端在应用服务器中(如EJB服务器)被运行时,分布式事务应当被自动处理;但是对JMS客户端来说,显式的通过程序使用JTS也是可能的。 1.4.6 Java命名和目录接口API(JNDI) JMS客户端使用JNDI API查找已配置的JMS对象。JMS管理员使用提供商提供的工具来创建和配置这些对象。 通过将特定提供商的工作代理给管理员最大化了客户端的可移植性。它也导致了更多的可管理应用,因为客户端不需要将管理用的值嵌入到他们的代码中。 1.4.7 J2EE平台 J2EE平台规范(版本1.3)要求将JMS API作为J2
27、EE平台的一部分。J2EE平台规范对JMS的实现提出了附加的要求,这些要求超出了JMS规范中描述的要求,包括既要支持点对点域又要支持发布/订阅域。 12 / 66 1.4.8 JMS和EJB组件的集成 J2EE平台和EJB规范描述了要集成到J2EE平台的JMS提供商实现的附加要求。一个关键的需求集是JMS消息生产和JMS消息消费如何与容器管理事务的事务需求进行交互。参考这两个规范来来了解JMS集成的所有要求。 JMS API规范没有说明实现这些集成要求的模型。因此,不同的JMS提供商实现可以使用不同的方式来实现与J2EE平台的集成,以及支持EJB的要求。 将来,JMS集成到J2EE平台的集成点
28、将用J2EE连接器架构来提供。 1.5 JMS1.1的新特性是什么? 在JMS的以前版本中,用于点对点和Pub/Sub域的客户端编程都是类似的,但使用不同的类层次。在JMS1.1中,现在有一个不依赖域的方式来编写客户端应用。这有以下几个好处: z 对于客户端程序员,简化了编程模型。 z 提供了在同一事务中使用队列(Queue)和主题(topic)的能力,现在可以在同一个会话内创建它们。 z 对于JMS提供商,通过线程池管理增加了优化实现的机会。 为使用这些优点,JMS客户端开发者需要使用不依赖域的或“通用”的API。将来,某些域专有的API可能被废弃。 在JMS1.1中,所有来自JMS1.0.
29、2b的类和方法仍然被保留以提供向后的兼容性。两种消息域的语义也被保留;PTP域和Pub/Sub域的行为仍然是相同的,正如在第5章“JMS 点对点模型”和第6章“JMS 发布/订阅模型”描述的一样。 为了详细的了解本规范的变更情况,参见第11章“变更历史”。 2 架构 2.1 概述 本章描述基于消息的应用的环境和JMS在环境中扮演的角色。 2.2 什么是JMS应用 JMS应用由以下部分组成: z JMS客户端发送和接收消息的Java语言程序。 z 非JMS客户端使用消息系统的本地客户端API而不是JMS的API,如果应用先于JMS,那么它很可能既包含JMS又包含非JMS客户端。 z 消息每个应用
30、定义一系列的消息,这些消息用于在客户端之间交换信息。 z JMS提供商它是一个消息系统,它实现了JMS以及其他的完整消息产品所需要的管理和控制功能。 13 / 66 z 被管理的对象被管理的对象是预先配置好的JMS对象,它由管理员为客户端使用而创建。 2.3 管理 期望JMS提供商和它们的后台消息技术有大的区别。也期望在如何安装和管理提供商的系统也有大的区别。 如果JMS客户端是可移植的,那么他们必须与提供商专有的方面隔离开来。通过定义JMS被管理的对象来做到隔离,这些对象由提供商的管理员创建和客户化,接下来由客户端使用。通过JMS接口来使用它们的客户端是可移植的。管理员使用提供商专有的工具来
31、创建它们。 有两种类型的JMS被管理对象: z ConnectionFactory这个对象用于客户端来创建和提供商的连接。 z Destination这个对象用于客户端来指定发送消息的目的地,也是接收消息的来源。 被管理对象被管理员放置在JNDI命名空间。JMS客户端通常在它的文档中注上它要求的JMS被管理对象和这些对象的JNDI名字应当如何提供给它。 图21解释了JMS管理如何工作。 图21 JMS管理 2.4 两种消息风格 JMS应用既可以使用PTP风格又可以使用Pub/Sub消息风格,在后面的章节中会有更详细的描述。应用也可以将两种风格组合到一个应用中。消息的这两种风格常被称为消息域。J
32、MS提供了这两种消息域,因为它们代表了两种通用的消息模型。 当使用JMS API时,开发人员可以使用两种消息模型的接口和方法。当使用接口时,消息系统的行为可能会稍有不同,因为两种消息域有不同的语义。这些语义的差别在第5章“JMS点对点模型”和第6章“JMS 发布/订阅模型”中描述。 14 / 66 2.5 JMS接口 JMS基于一系列通用的消息概念。每个JMS消息域PTP和Pub/Sub也为这些概念定义了各自的接口集。 表21 PTP和Pub/Sub接口的关系 JMS公共接口 PTP专有接口 Pub/Sub专有接口 ConnectionFactory QueueConnectionFactor
33、y TopicConnectionFactory Connection QueueConnection TopicConnection Destination Queue Topic Session QueueSession TopicSession MessageProducer QueueSender TopicPublisher MessageConsumer QueueReceiver,QueueBrowser TopicConsumer JMS通用接口提供了一个独立于PTP和Pub/Sub消息域的域视图。鼓励JMS客户端程序员使用这些接口来创建他们的客户端程序。 下面列出了这些JMS
34、概念的简要定义。参见第4章“JMS 通用工具”来详细了解这些概念。 对于两种消息域的差别的详细内容,参见第5章“JMS点对点模型”和第6章“JMS发布/订阅模型”。 z ConnectionFactory客户端使用这个被管理对象来创建一个Connection。 z Connection一个到JMS提高商的活动连接。 z Destination封装了消息目的地标识的被管理对象。 z Session一个用于发送和接收消息的单线程上下文。 z MessageProducer一个由Session创建用于往目的地发送消息的对象。 z MessageConsumer一个由Session创建用于接收发送到目
35、的地的消息的对象。 图21 JMS对象间关系概览 在这个文档中使用的术语“消费”是指通过JMS客户端接收消息;也就是说,一个JMS提供商已经收到一个消息并将它给了它的客户端。由于JMS支持同步和异步接收消息,因15 / 66 此术语“消费”在不需要区分它们的时候使用。 术语“生产”用作发送消息的最通用的术语。它指给予JMS提供商一个消息以转发到一个目的地。 2.6 开发一个JMS应用 广义的讲,一个JMS应用是一个或多个交换消息的JMS客户端。应用也涉及非JMS客户端;但是,这些非JMS客户端使用JMS提供商的本地API而不是JMS的API。 一个JMS应用可以被架构和部署为一个单元。在许多情
36、况下,JMS客户端是被逐渐增加到线程的应用中的。 应用使用的消息定义可以来源于JMS,或者他们可能已经由应用的非JMS部分定义了。 2.6.1 开发一个JMS客户端 典型的JMS客户端执行下面的JMS设置过程: z 使用JNDI来发现ConnectionFactory对象。 z 使用JNDI来发现一个或多个Desitination对象。 z 使用ConnectionFactory来创建一个具有消息转发约束的JMS Connection。 z 使用Connection来创建一个或多个JMS Session。 z 使用Session和Destination来创建需要的MessageProducer
37、和MessageConsumer。 z 告诉Connection开始转发消息。 此时,客户端有了生产和消费消息的基本的JMS设置。 2.7 安全 JMS没有提供控制或配置消息完整或消息私密的特性。 这期望由JMS提供商来提供。也期望由提供商专有的管理工具来配置这些服务。客户端将得到正确的安全配置作为他们使用的被管理对象的一部分。 2.8 多线程 JMS已经要求它的所有对象都支持并发誓要。由于支持并非访问通常会增加一些成本和复杂性,所以JMS限制了那些很自然要被多线程客户端并发访问的对象的要求。其他的都被设计成在一个时间只能被一个逻辑线程访问。 表22 支持并发使用的JMS对象 JMS对象 支持
38、并非使用 Destination YES ConnectionFactory YES Connection YES Session NO MessageProducer NO 16 / 66 MessageConsumer NO JMS定义了一些特殊的规则来限制Session的并发使用。由于他们要求比在这里呈现的更多的JMS知识,所以他们将在后面描述。这里我们将描述他们必须遵守的基本原理。 有两个原因要限制并发访问Session。第一个,Session是支持事务的JMS实体。实现多线程的事务是非常困难的。第二,Session支持异步的消费消息。重要的是JMS不要求用于消费异步消息的客户端代码有
39、处理多个并发的消息的能力。另外,如果Session被设置有多个异步的消费者,那么不强迫客户端处理这些并发执行的分散的消费者。这些约束使得通常的客户端更加容易地使用JMS。更专业的客户端可以通过使用多个会话来获得他们期望的并非性。 2.9 触发式客户端 某些客户端被设计成被周期性的唤醒来处理等待它们的消息。一个基于消息的应用触发机制常和客户端的风格一起使用。触发器通常是等待消息的起点,等等。 JMS没有提供触发客户端执行的机制。某些提供商可以通过它们的管理工具提供这样的触发机制。 2.10 请求/回复 JMS提供了JMSReplyTo消息头字段来指定回复的消息应当被发送到的目的地。回复的JMSC
40、orrelationID头字段可以被用于引用原始的请求。参见3.4章节“消息头字段”了解详细信息。 另外,JMS提供了创建临时队列和主题的功能,它可以用作回复的唯一目的地。 企业消息产品支持许多请求/回复风格,从简单的“一个消息请求产生一个消息回复”到“一个消息请求产生一串回复,回复消息来自多个应答者”。JMS不仅架构了一个特定的请求/回复抽象,而且提供了基本的工具,许多企业消息产品可以基于它来构建。 为了方便,JMS为PTP和Pub/Sub域定义了请求/响应帮助类(这些类用JMS实现),它实现了请求/回复的基本形式。JMS提供商和客户端可以提供更加专业的实现。 3 JMS消息模型 3.1 背
41、景 企业消息产品把消息看作是轻量级的实体,它由消息头和消息体组成。消息头包含了用于消息路由和标识的字段;消息体包含了被发送的应用数据。 通常情况下,消息的定义随产品的不同有很大的差别。主要的差别是消息头的内容和语义。某些产品使用自描述的规范的消息数据编码;其他的可能将数据认为是完全不透明的。某些产品为能被用于标识和解释消息内容的消息描述提供了存储池;其他的就没有。 对JMS来讲捕获偶尔冲突的消息模型组合的范围是非常困难的。 17 / 66 3.2 目标 JMS消息模型有下列目标: z 提供一个单一的统一的消息API。 z 提供一个API,它能创建匹配现存的非JMS应用使用的格式的消息。 z 支
42、持异构应用的开发,异构应用涵盖操作系统、机器架构和计算机语言。 z 支持包含java对象的消息。 z 支持包含可扩展标签语言(XML)页面的消息(参见http:/www.w3.org/XML)。(译者注:就是消息是XML) 3.3 JMS消息 JMS消息由以下部分组成: z 消息头所有的消息都支持相同的头字段集。头字段包含了客户端和提供商都要使用的用于标识和路由消息的值。 z 属性除了标准的头字段外,消息提供了一个内置的功能来向消息增加可选的头字段。 应用专有属性为消息增加应用专有的头字段提供的机制。 标准属性JMS定义的一些标准属性,它们相当于可选的头字段。 提供商专有属性在集成JMS客户端
43、和JMS提供商本地客户端时可能会用到提供商专有的属性。JMS为这些属性定义了命名规范。 z 消息体JMS定义了几个消息体类型,这些类型覆盖了大部分当前使用的消息风格。 3.4 消息头字段 下面的子章节描述了所有的消息头字段。消息的头被完整地转发到所有的JMS客户端。JMS没有定义那些转发到非JMS客户端的头字段。 3.4.1 JMSDestination JMSDestination包含了消息被发往的目的地。 当消息被发送时,忽略这个字段。在发送完成后,这个字段容纳由发送方法指定的目的地对象。 当消息被接收时,它的目的地的值必须等于发送时赋给的值。 3.4.2 JMSDeliveryMode
44、JMSDeliveryMode包含了消息发送时指定的转发模式。 当消息被发送时,这个字段被忽略。在完成发送后,它包含了由发送方法指定的转发模式。 18 / 66 参见4.7章节“消息转发模式”了解更详细的信息。 3.4.3 JMSMessageID JMSMessageID包含了一个用于唯一标识由提供商发送的每个消息。 当消息被发送时,JMSMessageID被忽略。当发送方法返回时,这个字段包含了一个提供商赋予的值。 JMSMessageID是一个String值,它用于在历史存储池中唯一标识消息的主键。唯一性的确切范围由提供商定义。它至少应当覆盖一个提供商安装的所有的消息,这里一个安装被连接
45、到一系列消息路由器。 所有的JMSMessageID值必须以前缀“ID:”开始,没有要求跨不同提供商的消息ID值的唯一性。 由于消息ID需要花费时间来创建并增加了消息的长度,因此如果消息已经被给了一个暗示说英语不使用消息ID,那么JMS提供商可以优化过长的消息。JMSMessageProducer提供取消消息ID的暗示。当客户端设置消息生产者不使用消息ID时,它就是说它生产的消息不依赖消息ID的值。如果JMS提供商接受这个暗示,那么这些消息的消息ID必须设置为null;如果提供商不接受这个暗示,那么必须为消息ID设置一个唯一的值。 3.4.4 JMSTimestamp JMSTimestamp
46、包含了消息被发送的时间。但不是消息被真正转发的时间,因为真正的发送可能由于事务或其他的客户端消息排队而比较晚。 当一个消息被发送时,JMSTimestamp被忽略。当发生方法返回时,这个字段包含了调用和返回之间的某个时间值。它的格式是通常的java毫秒时间值。 由于时间戳需要花时间来创建,并增加了消息的长度,如果应用暗示不使用时间戳,那么某些JMS提供商可以优化消息的过载。JMS MessageProducer可以暗示不使用时间戳。当客户端设置生产者不使用时间戳,那么它就是说它生产的消息不依赖于时间戳的值。如果JMS提供商接受了这种暗示,那么这些消息的时间戳必须被设置成0;如果提供商不接受这种
47、暗示,则必须设置时间戳的值。 3.4.5 JMSCorrelationID 客户端可以使用JMSCorrelationID来链接消息。典型的用法就是将响应消息和请求消息链接起来。 JMSCorrelationID可以容纳下列的类型值: z 提供商专有的消息ID z 应用专有的String z 提供商本地的byte值 由于每个由JMS提供商发送的消息都被赋予了一个消息ID值,所以通过消息ID来链接消息是非常方便的。所有的消息ID值都必须以“ID:”作为前缀。 在某些情况下,应用(有几个客户端组成)需要使用应用专有的值来链接消息。例如,应用可以使用JMSCorrelationID来容纳一个引用一些
48、外部信息的值。应用专有的值不必以“ID:”19 / 66 为前缀;这是提供商生成消息ID值时的保留字符。 如果提供商支持关联ID的本地概念(native),那么JMS客户端可能需要给JMSCorrelationID赋特定的值来匹配非JMS客户端期望的值。Byte值就是用于这个目的。没有本地关联ID的JMS提供商不要求支持byte值(注:setJMSCorrelationIDAsBytes()和getJMSCorrelationIDAsBytes()可以抛出java.lang.UnsupportedOperationException)。为JMSCorrelationID使用byte值是不可移植
49、的。 3.4.6 JMSReplyTo 当消息被发送时,JMSReplyTo包含一个由客户支持的目的地。它是回复消息应当被发送到的目的地。 JMSReplyTo为null的消息可能是某个事件的通知消息或它们仅仅是发送者认为是有兴趣的数据。 JMSReplyTo有值得消息通常是期望响应的消息。响应是可选的;由客户端来决定。 3.4.7 JMSRedelivered 如果客户端收到一个设置了JMSRedelivered指示的消息,那么很可能但不能保证这个消息被转发过但没有确认。通常情况下,提供商必须设置JMSRedelivered,无论它是否正在重新转发一个消息。如果JMSRedelivered设置为true,那么它告诉消费应用这个消息可能已经被转发过,应用应当引起注意以免重复处理。参加4.4.11章节“消息确认”了解更详细的信息。 这个头字段对发送没有意义,不会被发送方法赋值。 3.4.8 JMSType JMSType包含了由客户端在发送消息时提供的消息类型标识。 某些JMS提供商使用消息存储池,这个池包含了由应用发送的消息的定义