用JMS编程.pdf
《用JMS编程.pdf》由会员分享,可在线阅读,更多相关《用JMS编程.pdf(58页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、2358 用用JMS编程编程 在本章中,我们将讨论 Java 消息发送服务(JMS)接口概念和 MQSeries 实施,以及如何使用 JMS 编程。我们将在消息发送编程模式的上下文中探讨 JMS 概念。2368.1 什么是什么是JMS?与 JDBC API for databases 一样,Java Message Services(JMS)是消息发送的标准 API。JMS 规范(1.0.2)由 Sun Microsystems 开发,IBM 和其他企业消息发送销售商、事务处理销售商以及 RDBMS 销售商都积极参与了开发过程。JMS 为 Java 程序与对消息发送系统对象进行各种操作的消息发
2、送系统进行互动提供了一个常见的模型。程序对消息发送系统对象进行的常见操作包括创建消息、发送消息、接收消息以及从企业消息发送系统中读取消息。JMS 为那些用 Java 开发的程序提供了一种访问这些消息发送系统操作的常见方法。JMS 具有两种消息发送风格,或者说它具有两个域:?一对一或点到点模型;?发布预订模型。JMS 仅仅是种规范。每个企业消息发送系统销售商都必须就其特定的消息发送系统提供实施规范的类。在本章中,我们将描述 JMS API 的 MQSeries 实施、讨论 JMS API 概念和 MQSeries 的JMS 实施能力,并讲解在可以利用 MQSeries JMS 实施的不同情境中如
3、何利用 MQSeries JMS。为什么要使用为什么要使用 JMS?JMS 标准非常重要,其原因在于:?它是第一个获取广泛跨行业支持的企业消息发送 API;?它提供的标准消息发送概念和惯例适用于广泛的企业消息发送系统,因而简化了企业应用程序的开发;?它可以利用现有的、企业证明成功可行的消息发送系统;?它添加了完全用现有非 JMS 客户机解释的新 JMS 客户机,从而允许您扩展现有的基于消息的应用程序;?它允许您可以编写便携性强的基于消息的商业应用程序。2378.2 概述概述 JMS 是定义 JMS 客户机如何访问企业消息发送产品功能的一系列接口和相关语义。我们这里所描述的消息是指企业应用程序所
4、使用的异步请求、报表或事件。它们既包含协同这些系统所需的重要信息;又包含着描述特定商业行为的精确格式化的数据。通过这些消息的交流,每个应用程序都能跟踪企业的发展。JMS 定义了一系列常见的企业消息发送概念和功能。它最大限度地减少了 Java 语言程序设计人员在使用企业消息发送产品前必须学会的概念集。也最大限度地加强了消息发送应用程序的便携性。JMS 标准虽然提供了独立于不同销售商的编程接口,但是并不定义出通讯协议。JMS 模型模型 JMS 定义了消息传递服务的一般视图。理解该视图,并弄清它是如何映射到底层的MQSeries 传输上的,相当重要。一般 JMS 模型是建立在 Sun 的 javax
5、.jms 包所定义的接口上的,请见图 81。238 图81 JMS模型 连接连接 连接提供了到底层传输的访问,并被用来创建会话。在 MQSeries 上下文中,连接提供了储存参数,如队列管理器名、远程主机名(在 Java 客户连接性中)等的地方。换言之,MQSeries JMS连接一般都在Java虚拟机之外分配MQSeries资源。连接也支持同时使用。连接可以提供以下好处:?包括与 JMS 供应方的开放式连接。它通常代表客户机和供应方服务端口之间的一个开放的 TCPIP 槽;?它的创建就是客户机认证发生之处;?它可以指定唯一的客户机标识符;239?它提供 ConnectionMetaData;
6、?它支持可选的 ExceptionListener。由于建立连接时完成了认证和通讯设置,因此连接相对来说是个重量级的 JMS 对象。大多数客户机都使用单一的连接进行消息发送。其他更先进的应用程序可能会使用几个连接。JMS 并不为使用多个连接而设计原因;但是,这样做可能有操作上的原因。JMS 客户机一般创建一个连接、一个或多个会话以及许多消息生成器和使用者。当创建连接时,它处在停止模式,这就是说没有消息再被送达。重点:重点:连接是在停止模式中创建的。通常,直到设置完成前,连接都处在停止模式中。在完成时,将调用连接的 start()方法,而消息则开始到达连接的使用者。此设置惯例可以在客户机仍在进行
7、设置过程中尽可能减少异步消息送达所带来的任何客户机混乱。连接可以立即启动,而设置可在随后进行。这样做的客户机必须在设置过程中就准备好处理异步消息送达。提示:提示:消息生成器可以在停止连接时发送消息。不是直接创建连接的,而是利用连接库建立的。库对象可以储存在 JNDI 名称空间中,从而将 JMS 应用程序与供应方特定信息隔离开来。连接库对象是利用 MQSeries JMS 管理工具 JMSAdmin 创建的。该工具使得管理员可以给 JNDI 名称空间定义 MQSeries JMS对象的 8 种类型。请参见第 8.4.9 节 利用JMSAdmin以VisualAge for Java管理JMS J
8、NDI对象(见本书第 260 页)。创建连接创建连接 客户机利用连接库来创建连接。要使用何种连接库类型取决于您想要哪种类型的连接:?就 PTP 连接而言,我们利用 QueueConnectionFactory 或 XAQueueConnectionFactory来获取 QueueConnection 或 XAQueueConnection;240?就 发 布 预 订 消 息 发 送 模 式 而 言,我 们 利 用 TopicConnectionFactory 或XATopicConnectionFactory 来获取 TopicConnection 或 XATopicConnection。为了
9、创建连接,我们应当进行以工作:?从 JNDI 名称空间接收库对象 JNDI API 向以 Java 编写的应用程序提供了命名和目录功能。它是利用 Java 的对象模型专门为 Java 设计的。利用 JNDI,Java 应用程序可以储存并接收任何类型的命名为 Java 的对象。另外,JNDI 提供进行标准目录操作的方法,如将属性与对象相关联并利用对象属性查找对象等。在此常见的 API 之后,可以无缝地插入不同的命名和目录服务供应方。这使得 Java应用程序可以通过各种各样的命名和目录服务来利用信息,如 LDAP、NDS、DNS和 NIS(YP)等,也使得 Java 应用程序可以与传统应用程序和系
10、统并存。在 JNDI 中,所有的命名和目录操作都是根据上下文进行的。没有绝对的根。因此,JNDI 定义了初始上下文,它是命名和目录操作名解析的起始点。一旦有了初始上下文,您就可以利用它来查看其他上下文和对象。?为了从 JNDI 名称空间接收对象,必须按照下面这段代码所显示的那样设置初始上下文:import javax.jms.*import javax.naming.*;import javax.naming.directory.*;java.util.Hashtable;Hashtable env new Hashtable();env.put(Context.INITIAL_CCONTEX
11、T_FACTORY,icf);env.put(Context.PROVIDER_URL,url);Context ctx new InitialDirContext(env);Icf 为初始上下文定义了库类,url 则定义了随上下文而变的 URL。?一旦获取了初始上下文,我们就可以利用 lookup()方法来从名称空间接收对象。下面这段代码从基于 LDAP 的名称空间接收 QueueConnectionFactory 名 firstQCF;QueueConnectionFactory qFactory;queueFactory(QueueConnectionFactory)ctx.lookup
12、(“cnfirstQCF”);?利用库对象来获取连接。241利用库对象的 createQueueConnection()方法来创建连接,请参见如下的例子:QueueConnection connection;connection qFactory.createQueueConnection();?启动连接 JMS 规范定义指出,应当在“停止”状态下创建连接。在您可以利用连接发送消息之前,必须显式启动连接。我们利用 start()方法启动连接,请参见如下的例子:connection.start();会话会话 为生成和使用消息提供上下文,包括用来创建消息生成器和消息使用者的方法。JMS 会话是生成
13、和使用消息的单线程上下文。尽管它可以在 Java 虚拟机之外分配供应方资源,但我们还是将其看作轻量级 JMS 对象。我们可以分别利用连接对象的 createQueueSession()或 createTopicSession()方法来创建会话。创建会话方法包括两个参数:1.可决定会话是否进行事务处理的 boolean。在事务处理的会话中,全部发送、或者全部接收作为一个单位的一组消息。在非事务处理会话中,分别发送或接收消息。2.定义识别模式的参数。请参见如下的例子:session connection.createQueueSession(false,Session.AUTO_ACKNOWLED
14、GE);这是用 AUTO_ACKNOWLEDGE 来创建非事务处理会话的最简单的情况。连接是线程安全的,但会话和由会话创建的对象不是线程安全的。我们建议多线程应用程序应当对每个线程都使用不同的会话。会话有以下几种用途:?它是消息生成器和使用者的库;?它提供了供应方优化的消息库;242?它既支持单一事务处理,又支持一系列将跨越生成器和使用者的库结合到原子单位的事务处理;?会话为它使用和生成的消息定义了连续序列;会话保存了它使用的消息,直到识别该消息;?会话串行化注册到消息使用者的消息侦听器。会话可以创建并服务于多个消息生成器和使用者。一种典型的用法就是在消息到达前一直在同步消息使用者上保持线程块
15、。然后线程可以使用一个或更多的会话消息生成器。如果一个客户机希望在其他客户机使用消息时具备一个生成消息的线程,那么该客户机就应当为生成线程使用另外的会话。一旦启动了连接,任何具有侦听器或注册消息侦听器的会话就会被赋予送达消息的控制线程。客户机代码从另一个控制线程利用会话或任何构成会话的对象都是错误的。唯一的例外就是使用会话或连接关闭方法。大多数客户机将它们的库自然地分成会话应当是比较容易的。该模型允许客户机简单启动并随着并行操作需要的增加而逐渐增加消息线程的复杂度。关闭方法是当另一个线程正在执行某个其他会话方法时唯一可以调用的会话方法。我们可以选择地指定会话为事务处理会话。每个事务处理会话都支
16、持单一系列的事务处理。每个事务处理会将一系列消息发送和一系列消息接收归组到原子库单元中。事实上,事务处理将会话的输入消息流和输出消息流组织到原子单位集中。当提交事务处理时,会确认输入的原子单位,同时发送与其相关联的输出原子单位。如果已经进行了事务处理回退,那么其发送的消息则被毁坏,会话的输入也被自动恢复。事务处理输入和输出单位的内容就是会话的当前事务处理中所生成和使用的那些消息。243我们可以利用会话的提交或回退方法完成事务处理。会话的当前事务处理的完成将自动开始下一个事务处理。其结果就是,事务处理会话总是具有一个当前事务处理,且其库就在当前事务处理中完成。消息生成器消息生成器 JMS 客户机
17、利用消息生成器发送消息到特定的目的地。我们通过传递目的地到会话对象提供的创建消息生成器方法,从而创建消息生成器。在点到点消息发送中,这将是利用 QueueSession 对象上的 createSender 方法所创建的QueueSender。QueueSender 通常是为特定队列创建的,因此所有利用该发送器发送的消息都会被发送到同样的目的地。我们利用队列对象指定目的地。队列对象即可以在运行时间中创建,也可以在 JNDI 名称空间中构造和储存。请参见如下的例子:Queue ioQueue;ioQueue (Queue).ctx.lookup(qLookUp);sender session.cr
18、eateSender(ioQueue);在发布预订消息发送中,这将是在 TopicSession 对象上利用 createPublisher 方法创建的 TopicPublisher。通常,Topic 是在创建 TopicPublisher 时指定的。在这种情况下,尝试去使用方法,该方法为未确认的 TopicPublisher,将生成 UnsupportedOperationException。请参见如下的例子:Topic topic;topic (Topic)ctx.lookup(“cnfirst.topic”);TopicPublisher pub session.createPublis
19、her(topic);客户机也可以选择不提供目的地而创建消息生成器。在这种情况下,目的地必须输入每个发送操作。这种风格的消息生成器一般用来根据请求的 replyTo 目的地向请求发送回复。客户机可以通过消息生成器为发送的消息指定默认的送达模式、优先级和使用期限。它也可以为每条消息指定送达模式、优先级和使用期限。244客户机可以为它发送的每条消息指定单位为毫秒的使用期限值。这个值定义了消息到期时间,也就是消息使用期限的和以及消息发送的 GMT 时间(对事务处理发送而言,这是指客户机发送消息的时间而不是提交事务处理的时间)。发送消息发送消息 消息是用消息生成器发送的。因此在点到点(PTP)模型中发
20、送消息时,您应当使用QueueSender 对象,而在发布预订模型中,您则应当使用 TopicPublisher 对象。在 PTP 模型中,应使用 QueueSender 的 send()方法发送消息。请参见如下的例子:outmessage session.createTextMessage();outmessage.setText(“Sample Message“);sender.send(outMessage);在发布预订模型中,应使用 TopicPublisher 对象的发布方法来发布消息。请参见如下的例子:pub.publish(outMessage);消息使用者消息使用者 消息使用者
21、是用来接收消息的。MessageConsumer 接口是所有消息使用者的父级接口。在 PTP 模型中,这将是 QueueReceiver。在发布预订模型中,这将是 TopicSubscriber。我们可以用消息选择器来创建消息使用者,消息选择器允许客户机根据消息选择器指定的标准选择消息子集。欲了解详细信息,请参见第 8.7 节消息选择器(见本书第 289页)。消息使用者客户机可以同步接收消息,也可以让消息在到达时异步送达。客户机可以利用其接收方法之一从消息使用者请求下一条消息。接收有几种不同的形式,允许客户机登记或等待下一条消息。客户机可以向消息使用者注册 MessageListener 对象
22、。当消息到达消息使用者时,它是通过调用 MessageListeners onMessage 方法来送达消息的。欲了解更多信息,请参见第 8.6节异步处理(见本书第 285 页)。245在 PTP 模型中,QueueReceiver 是利用 QueueSession 对象上的 createReceiver()方法创建的。该方法采用的是从何处接收消息定义的 Queue 参数。请参见如下的例子:QueueReceiver queueReceiver session.createReceiver(ioQueue);在发布预订模型中,TopicSubscriber 对象是利用 TopicSession
23、 对象的 createSubscriber()方法创建的。请参见如下的例子:TopicSubscriber sub session.createSubscriber(topic);接收消息接收消息 消息是用消息使用者接收的。在 PTP 消息发送中,应当用 QueueReceiver 对象来接收消息,而在发布预订消息发送中,则应当用 TopicSubscriber 对象来接收消息。在 PTP 模型中,您可以利用 QueueReceiver 对象的接收方法来接收消息。请参见如下的例子:Message inMessage queueReceiver.receive(800);指定的参数是以毫秒为单位
24、的超时。此方法发出调用,以接收指定超时间隔内到达的下一条消息。在发布预订模型中,我们利用 TopicSubscriber 的 receive()方法来接收预订。请参见如下的例子:Message inMsg sub.receive();这段代码执行了带有等待的获取方法。重点:重点:请注意,连接是线程安全的,但会话、消息生成器和消息使用者则不是。我们建议的做法是对每个应用程序线程使用一个会话。在 MQSeries 条款中,连接为临时队列提供了作用域。它也提供了地方,可以用来储存参数,该参数控制如何连接到 MQSeries。举例来说,这些参数就是队列管理器名和远程主机名(如果您使用 MQSeries
25、 Java 客户机连接的话)。会话包含 HCONN,因此定义了事务处理作用域。消息生成器和消息使用者包含 HOBJ,它定义了向其写入或从其读取的特定队列。请注意,正常的 MQSeries 规则是适用的。在任何给定时间上,每个 HCONN 只能进行一个单一的操作。因此,不能同时调用消息生成器或与会话相关的消息使用者。246这与 JMS 每个会话只有单一线程的限制是一致的。放置方法可以使用远程队列,但获取方法只能适用于本地队列管理器上的队列。一般 JMS 接口是进一步划分为更具体的版本子集,该子集为点到点以及发布预订行为。点到点版本如下:?QueueConnection QueueSession
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JMS 编程
限制150内