ibmMQ-第十二章

来源:互联网 发布:淘宝助手收费吗 编辑:程序博客网 时间:2024/04/30 00:28
第十二章 用Java编程目标学习使用WebSphere MQ for Java编程。12.1 概述WebSphere MQ for Java允许用Java 编程语言写成的程序直接访问WebSphere MQ Server,或作为一个WebSphere MQ Client连接到WebSphere MQ。12.2 平台WebSphere MQ for Java 产品可用于以下平台:AIXiSeries 和OS/400HP-UXLinuxSun Solarisz/OS 和OS/390 V2R9 或更高版本Windows 平台12.2.1 获得软件包WebSphere MQ base Java的最新版本的安装可以和WebSphere MQ同时安装。关于WebSphere MQ的安装可以参考下列资料:AIX 平台的《WebSphere MQ for AIX, V5.3 Quick Beginnings 》HP-UX平台的《WebSphere MQ for HP-UX, V5.3 Quick Beginnings》  OS/400平台的《WebSphere MQ for iSeries V5.3 Quick Beginnings 》Linux 平台的《WebSphere MQ for Linux for Intel and Linux for zSeries, V5.3 Quick Beginnings 》Solaris 平台的《WebSphere MQ for Solaris, V5.3 Quick Beginnings 》Windows 平台的《WebSphere MQ for Windows, V5.3 Quick Beginnings 》z/OS 平台的《WebSphere MQ for z/OS System Setup Guide 》WebSphere MQ base Java 被包含在下列Java的.jar文件中: com.ibm.mq.jar 这个jar文件支持所有的连接选项。 com.ibm.mqbind.jar 这个jar文件仅支持bindings连接,并不是在所有的平台都提供或支持,所以我们推荐在新应用程序中不要使用它。12.2.2 WebSphere MQ for Java的运行环境为了运行WebSphere MQ for Java,需要以下的软件:服务器端平台的WebSphere MQ ;服务器端平台的Java Development Kit(JDK);客户端平台的Java Development Kit 或Java Runtime Environment(JRE)或支持Java 的网络浏览器。12.2.2.1安装目录WebSphere MQ Java V5.3文件的安装目录如下表所示:平台目录AIX /usr/mqm/java/ z/OS & OS/390 install_dir/mqm/java/ iSeries & AS/400(R) /QIBM/ProdData/mqm/java/ HP-UX 和 Sun Solaris /opt/mqm/java/ Linux install_dir/mqm/java/ Windows systems \Program Files\IBM\WebSphere MQ\java 提示:install_dir 是产品安装的目录。在Linux 系统中,它可能是/opt,而在z/OS 和OS/390系统上,它可能是/usr/lpp。还提供了一些例子程序,例如安装验证程序(IVP)。下表中列出了不同平台的例子程序的目录结构。 平台目录AIX /usr/mqm/samp/java/basez/OS & OS/390 install_dir/mqm/java/samples/base iSeries & AS/400 /QIBM/ProdData/mqm/java/samples/base HP-UX and Sun Solaris /opt/mqm/samp/java/baseLinux install_dir/mqm/samp/java/base Windows systems \Program Files\IBM\WebSphere MQ\tools\Java\base 提示:install_dir 是产品安装的目录。在Linux 系统中,它可能是/opt,而在z/OS 和OS/390系统上,它可能是/usr/lpp。12.2.2.2环境变量产品安装完成后,您必须更新CLASSPATH环境变量,CLASSPATH中需要包含WebSphere MQ base Java和例子程序的目录,如下表所示:平台CLASSPATH的参考设置AIX CLASSPATH=/usr/mqm/java/lib/com.ibm.mq.jar: /usr/mqm/java/lib/connector.jar: /usr/mqm/java/lib: /usr/mqm/samp/java/base:HP-UX 和 Sun SolarisCLASSPATH=/opt/mqm/java/lib/com.ibm.mq.jar: /opt/mqm/java/lib/connector.jar: /opt/mqm/java/lib: /opt/mqm/samp/java/base:Windows systems CLASSPATH=mq_root_dir(CPDNL1)\java\lib\com.ibm.mq.jar; mq_root_dir\java\lib\connector.jar; mq_root_dir\java\lib\; mq_root_dir\tools\java\base\;z/OS & OS/390 CLASSPATH=install_dir(CPDNL2)/mqm/java/lib/com.ibm.mq.jar: install_dir/mqm/java/lib/connector.jar: install_dir/mqm/java/lib:install_dir/mqm/java/samples/base:iSeries & AS/400 CLASSPATH=/QIBM/ProdData/mqm/java/lib/com.ibm.mq.jar: /QIBM/ProdData/mqm/java/lib/connector.jar: /QIBM/ProdData/mqm/java/lib: /QIBM/ProdData/mqm/java/samples/base:Linux CLASSPATH=install_dir(CPDNL2)/mqm/java/lib/com.ibm.mq.jar: install_dir/mqm/java/lib/connector.jar: install_dir/mqm/java/lib:install_dir/mqm/samp/java/base:注意: 1.mq_root_dir 表示在Windows 系统的WebSphere MQ安装目录。通常是C:\Program Files\IBM\WebSphere MQ\。2.install_dir是产品的安装目录。 如果现有的应用程序依赖于com.ibm.mqbind,您必须要把com.ibm.mqbind.jar文件加到 classpath中。在某些平台还必须要更新下列附加的环境变量,如下表所示:平台环境变量AIX LD_LIBRARY_PATH=/usr/mqm/java/lib HP-UX SHLIB_PATH=/opt/mqm/java/lib Sun Solaris LD_LIBRARY_PATH=/opt/mqm/java/lib Windows systems PATH=install_dir\lib z/OS & OS/390 LIBPATH=install_dir/mqm/java/lib Linux LD_LIBRARY_PATH=install_dir/mqm/java/lib 注意: install_dir是产品的安装目录。注意:确保您追加的WebSphere MQ的变量不要覆盖现有的系统环境变量。如果覆盖了系统的环境变量,那么应用程序在编译或运行时将可能会失败。12.3 使用WebSphere MQ for Java应用程序连接到队列管理器后,就可以与访问WebSphere MQ对象(例如,队列)。队列管理器为其拥有的WebSphere MQ对象提供消息发送服务。使用WebSphere MQ classes for Java编程的方法依赖于使用的连接模式。连接的模式有两种,分别是客户连接模式和绑定模式。12.3.1客户机连接模式当WebSphere MQ classes for Java作为客户端时,与WebSphere MQ C客户端类似,但仍然存在如下区别:1,仅支持TCP/IP。2,不支持连接表。3,在启动时,不读取任何WebSphere MQ环境变量。4,通道的定义和环境变量信息都被存放在一个叫做Environment的类中,当连接时这些信息也可以被作为入口参数。5,错误和意外信息被写到MQException类说明的日志中。缺省错误信息被写到Java控制台。WebSphere MQ classes for Java 客户端不支持MQBEGIN和快速绑定。当利用客户机连接时,您必须指定其他一些环境属性,以便建立与队列管理器的连接。这些属性是: 主机名,即作为队列管理器主机的WebSphere MQ服务器的名字;以及通道名,即客户机连接通道的名字。另外,您也可以指定WebSphere MQ服务器监听的端口号。如果还没有指定端口号的话,那么将使用默认的端口号1414。12.3.2绑定模式在绑定模式(也称作服务器连接模式)中,与队列管理器的通讯利用的是进程间通讯。关键因素之一就是,要记住绑定模式只适用于那些运行在作为队列管理器主机的WebSphere MQ 服务器上的程序。利用绑定模式的程序不会从WebSphere MQ客户机机器上运行。换言之,应用程序被绑定在队列管理器所在的同一台机器上。绑定模式是访问WebSphere MQ 的一种快速而高效的方法。某些功能(如队列管理器的扩展架构事务处理协同)只在绑定模式下才可用。WebSphere MQ classes for Java的绑定模式与客户连接模式存在下列区别:1,忽略了MQEnvironmnet类所提供的大多数参数。2,绑定模式支持MQBEGIN和快速绑定。12.3.3 类库WebSphere MQ classes for Java 提供了一系列可以使Java applet和应用程序访问WebSphere MQ的类。WebSphere MQ for Java 包括以下类和接口:12.3.3.1类MQChannelDefinition该类用来传递有关连接队列管理器的信息至发送、接收和安全退出。当以绑定模式直接连接到WebSphere MQ时,此类不适用。MQChannelExit当调用发送、接收和安全退出时,该类定义传递到这些调用的上下文信息。该类的exitResponse 属性应当通过退出设置,以显示WebSphere MQ Client for Java 下一步应当采取何种行动。MQDistributionList该类代表开放式队列集,我们可以利用put()方法的单一调用发送消息至这些队列中。我们利用MQDistributionList 构造器或MQQueueManager 类的accessDistributionList()方法来做出该类的实例。MQDistributionListItem该类代表分配表中的单一项目(单一队列)。该类继承MQMessageTracker 类。MQEnvironment该类包含控制构建MQQueueManager 对象(及其相对应的到WebSphere MQ 的连接)环境的静态元素变量。由于调用MQQueueManager 构造器使该类值的集生效, 因此MQEnvironment 类的值应当在MQQueueManager 实例构建前设置。MQException该类包含WebSphere MQ 完成代码和错误代码常量的定义。以MQCC_开始的常量是WebSphere MQ 完成代码,而以MQRC_开始的常量则是WebSphere MQ 原因代码。只要出现WebSphere MQ错误,就会给出MQException。MQGetMessageOptions该类包含控制MQQueue.get()方法行为的选项。MQManagedObject该类是MQQueueManager、MQQueue 和MQProcess 类的超类。它提供查询并设置这些资源属性的能力。MQMessage该类代表WebSphere MQ 消息的消息描述器和数据。MQMessageTracker该类用来处理分配表中某个给定目的地的消息参数。MQDistributionListItem 继承它。MQPoolServices用作WebSphere MQ 连接默认ConnectionManager 的ConnectionManager,其实现可以使用该类。MQPoolServicesEvent只要添加或删除MQPoolToken 到MQEnvironment 控制的权标集,那么就可用该类来生成一个事件。当默认的ConnectionManager 改变时, 即会生成MQPoolServicesEvent。MQPoolToken 该类可被用来提供默认的连接集合。MQProcess 该类为WebSphere MQ 进程提供查询操作。MQPutMessageOptions该类包含控制MQQueue.put()方法行为的选项。MQQueue该类为WebSphere MQ 队列提供查询、设置、放置和获取操作。查询和设置能力继承自MQManagedObject。MQQueueManager 该类代表WebSphere MQ 的队列管理器。MQSimpleConnectionManager该类提供基本的连接集合功能。12.3.3.2接口WebSphere MQ for Jave 具有以下接口:MQReceiveExit该接口使得我们可以用WebSphere MQ for Java 检查并有可能修改从队列管理器接收的数据。当以绑定模式直接连接到WebSphere MQ 时,该接口不适用。MQSecurityExit该接口使得我们可以尝试定制连接到队列管理器时出现的安全流。当以绑定模式直接连接到WebSphere MQ 时,这一接口不适用。MQSendExit该接口使得我们可以检查并有可能修改用WebSphere MQ Client for Java 发送到队列管理器的数据。当以绑定模式直接连接到WebSphere MQ 时,这一接口不适用。12.4用WebSphere MQ Java API开展工作我们在本节中将探讨利用WebSphere MQ Java API 进行编程的方法。12.4.1 设置连接在本节中,我们将看看绑定模式和客户机连接模式是如何实现的。我们假定从设计的观点出发,您已经决定用绑定模式或客户机连接模式实现,下面我们就来讲解一下应当如何来实现的方法。我们通过MQQueueManager 类的构造器调用获得到队列管理器的连接。在这个时候,我们所获得连接的类型是由MQEnvironment 类的某些静态字段决定的。区别不同连接模式的静态字段设置分别是主机、通道、userId 和口令。在这些用以连接到队列管理器的MQEnvironment 字段中,最能区别出绑定模式和客户机连接模式的两个字段设置就是主机和通道。在绑定模式中,除了userId 和口令字段外,您不必为这些字段中的任何一个设置值。您也可以选择在绑定模式中设置它们。MQEnvironment.hostName对客户机连接而言,我们应当将此设为队列管理器所在主机的主机名。由于该主机名用于到队列管理器运行机器的TCP/IP 连接,因此其值不区分大小写,请看下面的例子:MQEnvironment.host = “machinename.dmain.com” ;MQEnvironment.channel这是客户机连接通道的名。该字段的值是区分大小写的。一般说来,它就是队列管理器下面服务器连接通道的名。是一个双向链接,它使在客户机和队列管理器之间的MQI 调用和回复成为可能。对客户机连接而言,我们应当将其设为应用程序尝试连接的队列管理器下面服务器连接通道的名,请看下面的例子:MQEnvironment.channel = “JAVA.CLIENT.CHNL”;MQEnvironment.port端口号是一个可选字段。在默认情况下,客户机会尝试在主机的1414 号端口上连接到队列管理器。1414 号端口是WebSphere MQ监听器默认使用的端口。如果该端口号与默认的不同,那么您可以用MQEnvironment.port 字段来指定端口号,请看下面的例子:MQEnvironment.port = nnnn;MQEnvironment.userId 和MQEnvironment.passworduserId 和口令字段在默认情况下是空的。您可以通过设置userId 和口令字段的值来指定userId 和口令,请看下面的例子:MQEnvironment.userId = “userXYZ” ;MQEnvironment.password = “password” ;MQEnvironment.properties这是定义WebSphere MQ 环境的关键值对的散列表。如果您不是使用VisiBroker 连接的话,那么就应当将该字段在绑定和客户机连接情况下都做如下设置:MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_WEBSPHERE MQMQEnvironment 类中的变量控制着到队列管理器的连接调用。设置连接到队列管理器的第一步就是根据连接模式的类型来设置MQEnvironment 字段, 我们通过创建MQQueueManager 类的新的实例、发出MQQueueManager 类的构造器调用来获得到队列管理器的连接。MQQueueManager 类有过载的构造器。我们要根据创建MQQueueManager 类新实例时提供的参数来调用合适的构造器建立连接。在最简单的情况中,您可以提供队列管理器名作为字符串,从而创建QueueManager 类的新实例,请看下面的例子:MQQueueManager qmgr = new MQQueueManager(“ITSOG.QMGR1”) ;在这里,ITSOG.QMGR1是队列管理器名。上面的方法在绑定模式和客户机连接模式中都有效。在第二种方法中,您可以提供队列管理器名以及具有设置环境选项关键值对的散列表,从而创建MQQueueManager 类的新实例。利用这种方法时,提供的属性会覆盖MQEnvironment 类中设置的值。如果您希望在队列管理器到队列管理器的情况下设置环境值,那么您就可以使用此方法。请看下面的例子:MQQueueManager qmgr = new MQQueueManager(queueManagerName ,propertiesHashTable);第三种方法就是通过提供队列管理器名和队列管理器打开选项,从而创建MQQueueManager 类的新实例(它是一个整数字段)。只有在绑定模式中才能使用该方法。选项字段使您可以在快速绑定或正常绑定间作出选择。请看下面的例子:MQQueueManager qmgr = new MQQueueMager(queueManagerName ,MQC.MQCNO_FASTPATH_BINDING ) ;12.4.2 打开队列为了对队列进行操作,我们首先应当通过打开队列以获得队列句柄或队列对象。打开队列有两种方法。我们可以利用MQQueueManager 对象的accessQueue 方法,也可以通过调用MQQueue 类的构造器。这两种不同调用的形式如下:MQQueue queue = qmgr.accessQueue(“qName’, openOption, “qMgrName” ,“dynamicQname”, “alternateUserId”);使用MQQueue 类构造器的第二种方法,需要添加一个队列管理器参数,MQQueue queue = new MQQueue(qmgr, “qName’, openOption, “qMgrName” ,“dynamicQname”, “alternateUserId”);WebSphere MQ 将在打开队列过程中根据用户认证保证openOption 的有效性。MQQueue 类的对象代表着队列。它既拥有有助于消息发送(即放置、获取、设置、查询)的方法,也有对应于队列属性的属性。12.4.3 处理WebSphere MQ消息MQMessage 类的对象代表着将被放置到队列上或将从队列获取的消息。它既包括应用程序数据,又包括MQMD。既具有对应于MQMD 字段的属性,又具有向消息写入或从消息读取不同数据类型的应用程序数据的方法。在应用程序中,MQMessage 代表着一个缓冲区。应用程序不必声明缓冲区的大小,因为它会随着写入的数据而不断改变。但是,如果消息大小超过了队列的MaximumMessageLength 属性的话,您就不能将消息放到队列中。为了创建消息,您应当创建MQMessage 类的新实例。我们利用writeXXX 方法根据特定应用程序数据类型将应用程序数据写入消息。数字和字符串等数据类型格式可以通过characterSet 和编码等MQMD 属性来控制。我们可以在放置消息到队列上之前设置MQMD 字段,也可以在从队列获取消息时读取MQMD 字段。应用程序通过设置合适的放置或获取操作选项,从而控制着消息放置到队列或从队列获取消息的方式。我们通过设置合适的放置消息选项值来控制消息放置到队列的方式。同样,我们也可以通过设置合适的获取消息选项来控制从队列接收消息的方式。放置消息选项消息放置到队列上的方式是由MQPutMessageOptions 类实例的选项字段的值来决定的。我们可以利用WebSphere MQ 常量接口 MQC 的MQPMO 结构来设置选项的值。请看下面的例子:MQPutMessageOptions pmo = new MQPutMessageOption();MQPutMessageOptions 类的实例,其选项属性的值设置为默认值。这在大多数简单消息发送情境中都已经足够了。您可以利用WebSphere MQ 常量接口MQC 的MQPMO 结构来设置任意特定的选项,例如:pmo.options = pmo.options + MQC.MQPMO_NEW_MSG_ID上面的例子设置了选项字段的值,指令队列管理器为消息生成新的消息ID 并将其设为MQMD 的MsgId 字段。获取消息选项从队列接收消息的方式是由MQGetMessageOptions 类实例的选项字段的值决定的。我们可以利用WebSphere MQ Constants MQC 的MQOO 结构来设置选项的值。请看下面的例子:MQGetMessageOptions gmo = new MQGetMessageOption();MQGetMessageOptions 类的新实例将选项属性的值设为默认值。您可以利用MQPOO 结构来设置合适的获取消息选项。请看下面的例子:gmo.options = gmo.options + MQC.MQGMO_NO_WAIT;以上选项指定了如果队列上没有消息的话,那么获取消息调用将立即返回。发送消息我们利用MQQueue 类的put(MQMessage message)或put(MQMessage message,MQPutMessageOptions pmo)方法来发送消息。放置方法调用控制着消息放置到队列上的方式。获取消息我们利用MQQueue 类的get ( MQMessage message ) 或get ( MQMessage,MQGetMessageOptions gmo)、get(MQMessage, MQGetMessageOptions gmo, int maxMessageSize)方法来从WebSphere MQ 队列接收消息。所有从给定MQQueueManager 到WebSphere MQ的调用都是同步的。注意:如果您进行带有等待的获取调用的话,那么直到获取调用完成之前,所有其他利用相同MQQueueManager 的线程都将被封锁,不能发出进一步的WebSphere MQ调用。如果您需要多线程同时来访问WebSphere MQ的话,那么每个线程都必须创建其自己的MQQueueManager 对象。如果没有指定MaxMessageSize 的话,那么将自动调整消息缓冲区长度为将要到达的消息的大小。如果您以获取方法调用使用MaxMessageSize 的话,那么该调用将能接收最大的消息。如果队列上的消息比它还要大的话,那么就会出现下面两种情况之一:1. 如果MQC.MQGMO_ACCEPT_TRUNCATED_MSG 标记在MQGetMessageOptions对象的选项元素变量中得到设置的话,那么将根据指定缓冲区的大小向消息填充最多的数据,并且会返回完成代码为MQException.MQCC_WARNING 和原因代码为MQException.MQRC_TRUNCATED_MSG_ACCEPTED的结果。2. 如果没有设置MQC.MQGMO_ACCEPT_TRUNCATED_MSG 标记的话,那么消息将被留在队列上,并且会返回完成代码是MQException.MQCC_WARNING 和原因代码是MQeception.MQRC_TRUNCATED_MSG_FAILED 的结果。12.5应用程序开发在本节中,我们将探讨发送-遗忘、请求/回复和消息分组点到点消息发送模式的实现。在点到点模式中,应用程序成对活动。我们称作发送器的发送应用程序将消息放置在发送方的WebSphere MQ 应用程序队列上。在目的地系统或接收方上,我们称作接收器的应用程序从WebSphere MQ 应用程序队列接收消息。因此,发送器和接收器应用程序是成对活动的,实现了在来源和目的地系统之间的数据移动或消息发送。在我们所举的这些例子中,用到了到队列管理器的客户机连接。在这些例子中用到的WebSphere MQ 对象是在主机ITSOG 上称作ITSOG.QMGR1 的队列管理器。用于客户机连接的通道是JAVA.CLIENT.CHNL,端口就是默认端口1414。我们所用的应用程序队列是SAMPLE.QUEUE。12.5.1简单的消息发送器应用程序我们的第一个点到点客户机程序将创建一个简单的消息并发送它到WebSphere MQ 队列。我们还将讲解处理发送器发送消息的接收器程序。有关步骤如下:调入WebSphere MQ Java API package;为客户机连接设置环境属性;连接到队列管理器;为打开WebSphere MQ 队列设置选项;为发送消息打开应用程序队列;设置选项,放置消息到应用程序队列上;创建消息缓冲区;使用用户数据和任何消息描述器字段准备消息;放置消息到队列上。以下程序PtpSender.java 就是将在应用程序队列上发送消息的发送器应用程序:import com.ibm.mq.*;public class Typesetter {public static void main(String args[]) {try{String hostName = "ITSOG" ;String channel = "JAVA.CLIENT.CHNL" ;String qManager = "ITSOG.QMGR1" ;String qName = "SAMPLE.QUEUE" ;/*设置MQEnvironment 属性以便客户机连接*/MQEnvironment.hostname = hostName ;MQEnvironment.channel = channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/MQQueueManager qMgr = new MQQueueManager(qManager) ;/*设置打开选项以便打开用于输出的队列,如果队列管理器正在停止,我们也已设置了选项去应对不成功情况。*/int openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING ;/*打开队列*/MQQueue queue = qMgr.accessQueue(qName,openOptions,null,null,null);/*设置放置消息选项我们将使用默认设置*/MQPutMessageOptions pmo = new MQPutMessageOptions();/*创建消息,MQMessage 类包含实际消息数据的数据缓冲区,和描述消息的所有MQMD 参数*//*创建消息缓冲区*/MQMessage outMsg = new MQMessage(); /*设置MQMD 格式字段*/outMsg.format = MQC.MQFMT_STRING ; /*准备用户数据消息*/String msgString = "Test Message from PtpSender program ";outMsg.writeString(msgString);/*在队列上放置消息*/queue.put(outMsg, pmo);/*提交事务处理*/qMgr.commit();System.out.println(" The message has been Successfully put!\n");/*关闭队列和队列管理器对象*/queue.close();qMgr.disconnect();}catch (MQException ex){System.out.println("An MQ Error Occurred: Completion Code is :\t" +ex.completionCode + "\n\n The Reason Code is :\t" + ex.reasonCode );ex.printStackTrace();}catch(Exception e) {e.printStackTrace();} }}12.5.2简单的消息接收应用程序我们的下一个点到点客户机程序是消息接收器应用程序,它获取PtpSender 应用程序所发送的消息并在控制台上将消息打印出来。有关步骤如下:调入WebSphere MQ Java API package;为客户机连接设置环境属性;连接到队列管理器;为打开WebSphere MQ 队列设置选项;为获取消息打开应用程序;设置选项,从应用程序队列获取消息;创建消息缓冲区;从队列获取消息到消息缓冲区;从消息缓冲区读取用户数据并在控制台上显示。以下程序PtpReceiver.java 就是将从应用程序队列上获取消息的接收应用程序:import com.ibm.mq.* ;public class PtpReceiver {public static void main(String args[]) {try{String hostName = "ITSOG" ;String channel = "JAVA.CLIENT.CHNL" ;String qManager = "ITSOG.QMGR1" ;String qName = "SAMPLE.QUEUE" ;/设置 MQEnvironment 属性以便客户机连接*/MQEnvironment.hostname = hostName ;MQEnvironment.channel = channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/MQQueueManager qMgr = new MQQueueManager(qManager) ;/*设置打开选项以便打开用于输出的队列,如果队列管理器停止,我们也已设置了选项去应对不成功情况*/int openOptions = MQC.MQOO_INPUT_SHARED |   MQC.MQOO_FAIL_IF_QUIESCING ;/*打开队列*/MQQueue queue = qMgr.accessQueue(qName,openOptions,null,null,null);/*设置放置消息选项*/MQGetMessageOptions gmo = new MQGetMessageOptions();/*在同步点控制下获取消息*/gmo.options = gmo.options + MQC.MQGMO_SYNCPOINT ; /*如果在队列上没有消息则等待*/gmo.options = gmo.options + MQC.MQGMO_WAIT ; /*如果队列管理器停顿则失败*/gmo.options = gmo.options + MQC.MQGMO_FAIL_IF_QUIESCING ; /*设置等待的时间限制*/gmo.waitInterval = 3000 ; /*创建MQMessage 类*/MQMessage inMsg = new MQMessage(); /*从队列到消息缓冲区获取消息*/queue.get(inMsg, gmo) ;/*从消息读取用户数据*/String msgString = inMsg.readString(inMsg.getMessageLength());System.out.println(" The Message from the Queue is : " + msgString);/*提交事务*/qMgr.commit();/*关闭队列和队列管理器对象*/queue.close();qMgr.disconnect();}catch (MQException ex){System.out.println("An MQ Error Occurred: Completion Code is :\t" +ex.completionCode + "\n\n The Reason Code is :\t" + ex.reasonCode );ex.printStackTrace();}catch(Exception e) {e.printStackTrace();}}}12.5.3请求/回复在请求/回复消息发送模式中,一个应用程序发送一条消息(请求消息)到另一个回复应用程序(回复生成器)再到请求消息。生成回复的应用程序获取请求消息、处理请求,并向请求应用程序发出回复。回复发送到由请求消息的消息标题属性replyToQueueManager 指定的队列。请求应用程序在放置消息到队列上之前会在请求消息上设置这些消息标题属性。请求应用程序让队列管理器生成唯一的messageId,以及回复应用程序拷贝请求消息的messageId 到回复消息的correlationId 上。请求应用程序使用回复消息的correlationId 值,将回复映射回原始的请求。我们将利用一对简单的应用程序来讲解请求回复模式。第一个应用程序(我们称作请求器)放置一条简单的消息到队列(请求队列)上。请求器在放置请求消息到队列上之前会在请求消息上设置replyToQueue 和replyToQueueManager 消息标题属性。而后,它将打开回复队列并等待correlationId 匹配已发出请求消息的messageId 值的消息。服务于请求消息的回复应用程序获取消息,准备回复消息,并将它发送到请求消息指定的队列管理器下的回复队列上。它还将从请求消息拷贝messageId 到回复消息的correlationId消息标题字段。应用程序Requester.java 即发送请求消息并且等待从回复应用程序获得回复的应用程序。有关步骤如下:调入必要的包;为客户机连接设置MQEnvironment 属性;连接到队列管理器;打开请求队列以获得输出;设置放置消息选项;- 准备请求消息;- 设置到队列名的回复;设置到队列管理器名的回复;放置请求消息到请求队列上;关闭请求队列;打开回复队列以获得输入;设置获取消息选项;- 设置选项,匹配回复消息上的correlationID;- 用等待(等待匹配correlationId 的回复消息)在回复队列上发出获取。注意:我们建议您为回复消息在获取调用上使用确定的等待时间。等待间隔可以设为系统所允许的等待回复的最大时间。import com.ibm.mq.*;public class Requester {public static void main(String args[]) {try{String hostName = "ITSOG" ;String channel = "JAVA.CLIENT.CHNL" ;String qManager = "ITSOG.QMGR1" ; String requestQueue = "SAMPLE.REQUEST" ;String replyToQueue = "SAMPLE.REPLY" ;String replyToQueueManager = "ITSOG.QMGR1" ;/*设置MQEnvironment 属性以便客户机连接*/MQEnvironment.hostname = hostName ;MQEnvironment.channel = channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/MQQueueManager qMgr = new MQQueueManager(qManager) ;/*设置打开选项以便打开用于输出的队列,如果队列管理器停止,我们也已设置了选项去应对不成功情况*/int openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING ;/*打开打开队列*/MQQueue queue = qMgr.accessQueue(requestQueue,openOptions,null,null,null);/*设置放置消息选项,我们将使用默认设置*/MQPutMessageOptions pmo = new MQPutMessageOptions();pmo.options = pmo.options + MQC.MQPMO_NEW_MSG_ID ;pmo.options = pmo.options + MQC.MQPMO_SYNCPOINT ;/*创建消息缓冲区*/MQMessage outMsg = new MQMessage(); /*设置MQMD 格式字段*/outMsg.format = MQC.MQFMT_STRING ; outMsg.messageFlags = MQC.MQMT_REQUEST ;outMsg.replyToQueueName = replyToQueue;outMsg.replyToQueueManagerName = replyToQueueManager ;/*准备用户数据消息*/String msgString = "Test Request Message from Requester program ";outMsg.writeString(msgString);/*在队列上放置消息*/queue.put(outMsg, pmo);/*提交事务*/qMgr.commit();System.out.println(" The message has been Successfully put\n");/*关闭请求队列*/queue.close();/*设置打开选项以便队列响应*/openOptions = MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING ;MQQueue respQueue = qMgr.accessQueue(replyToQueue,openOptions,null,null,null);MQMessage respMessage = new MQMessage();MQGetMessageOptions gmo = new MQGetMessageOptions();/*在同步点控制下获取消息*/gmo.options = gmo.options + MQC.MQGMO_SYNCPOINT ; gmo.options = gmo.options + MQC.MQGMO_WAIT ; gmo.matchOptions = MQC.MQMO_MATCH_CORREL_ID;gmo.waitInterval = 10000 ;respMessage.correlationId = outMsg.messageId ;/*获取响应消息*/respQueue.get(respMessage, gmo);String response = respMessage.readString(respMessage.getMessageLength());System.out.println("The response message is : " + response);qMgr.commit();respQueue.close();qMgr.disconnect();}catch (MQException ex){System.out.println("An MQ Error Occurred: Completion Code is :\t" +ex.completionCode + "\n\n The Reason Code is :\t" + ex.reasonCode );ex.printStackTrace();}catch(Exception e) {e.printStackTrace();} }}12.5.4回复应用程序回复器应用程序Responder.java 处理来自请求队列的请求消息并发送回复到请求应用程序指定的请求队列上。import com.ibm.mq.* ;public class Responder {public static void main(String args[]) {try{String hostName = "ITSOG" ;String channel = "JAVA.CLIENT.CHNL" ;String qManager = "ITSOG.QMGR1" ;String qName = "SAMPLE.REQUEST" ;/*设置MQEnvironment 属性以便客户机连接*/MQEnvironment.hostname = hostName ;MQEnvironment.channel = channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/MQQueueManager qMgr = new MQQueueManager(qManager) ;/*设置打开选项以便打开用于输出的队列,如果队列管理器停止,我们也已设置了选项去应对不成功情况*/int openOptions = MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING ;/*打开队列*/MQQueue queue = qMgr.accessQueue(qName,openOptions,null,null,null);/*设置放置消息选项*/MQGetMessageOptions gmo = new MQGetMessageOptions();/*在同步点控制下取消息*/gmo.options = gmo.options + MQC.MQGMO_SYNCPOINT ; /*如果队列上没有消息则等待*/gmo.options = gmo.options + MQC.MQGMO_WAIT ;/*如果队列管理器停止则失败*/gmo.options = gmo.options + MQC.MQGMO_FAIL_IF_QUIESCING ; /*设置等待的时间限制*/gmo.waitInterval = 3000 ; /*创建MQMessage 类*/MQMessage inMsg = new MQMessage();/*从队列到队列缓冲区获取消息*/queue.get(inMsg, gmo) ;/*从消息读用户数据*/String msgString = inMsg.readString(inMsg.getMessageLength());System.out.println(" The Message from the Queue is : " + msgString);/*检查看消息是否属于类型请求消息并对该请求回复*/if (inMsg.messageFlags == MQC.MQMT_REQUEST ) {System.out.println("Preparing To Reply To the Request " );String replyQueueName = inMsg.replyToQueueName ;openOptions = MQC.MQOO_OUTPUT | MQC.MQOO_FAIL_IF_QUIESCING ;MQQueue respQueue = qMgr.accessQueue(replyQueueName,openOptions,inMsg.replyToQueueManagerName,null,null);MQMessage respMessage = new MQMessage() ;respMessage.correlationId = inMsg.MessageId;MQPutMessageOptions pmo = new MQPutMessageOptions();respMessage.format = MQC.MQFMT_STRING ;respMessage.messageFlags = MQC.MQMT_REPLY ;String response = "Reply from the Responder Program " ;respMessage.writeString(response);respQueue.put(respMessage, pmo);System.out.println("The response Successfully send ");qMgr.commit();respQueue.close();}queue.close();qMgr.disconnect();}catch (MQException ex){System.out.println("An MQ Error Occurred: Completion Code is :\t" +ex.completionCode + "\n\n The Reason Code is :\t" + ex.reasonCode );ex.printStackTrace();}catch(Exception e) {e.printStackTrace();}}}12.5.5消息分组应用程序可能需要将一系列更新分组归入一个工作单位中。这样的更新通常都是逻辑上相互关联的,为了保持数据的完整性,更新必须全部成功。如果一个更新成功而另一个更新失败的话,那么就会丢失数据完整性。WebSphere MQ 支持事务处理消息发送。当一个工作单位成功完成时就会被提交。在这时,所有在这个工作单位中所做的更新都将成为永久性的和不可逆的。如果工作单位失败的话,那么所有更新将都被取消。同步点协同就是工作单位在保持其完整性的情况下被提交或取消的过程。逻辑消息组中的逻辑消息是由GroupId 和MsgSeqNumber 字段确认的。MsgSeqNumber 从组中第一条消息由1 开始,如果消息不在组中,那么该字段的值就是1。组中的逻辑消息用途如下:保证排序(如果这在消息传输环境中不能得到保证的话)。允许应用程序将相似的消息分在一组(例如,那些必须全部由相同服务器实例来处理的消息)。组中的每条消息如果不是分为段的话,那么就是由一个物理消息构成的。每条消息在逻辑上都是分开的,只有MQMD 中的GroupId 和MsgSeqNumber 字段需要与组中的其他消息关联。MQMD 中的其他字段都是独立的;一些字段可能对组中所有消息都是相同的,而其他字段可能会不同。举例来说,组中的消息可能有着不同的格式名、CCSIDs、编码等。简单的组发送器应用程序我们的下一个程序范例GroupSender.java 将讲解如何发送在组中的消息。该应用程序将把10 条简单的消息作为工作单位中的一个组放置到队列上。有关步骤如下:调入必需的包;为客户机连接设置MQEnvironment 属性;连接到队列管理器;设置队列打开选项以获得输出;打开队列以获得输出;设置放置消息选项;- 设置选项,维护消息的逻辑顺序;- 设置选项,请求队列管理器生成GroupId;创建消息缓冲区;设置消息标题属性;- 设置messageFlags 属性,从而显示出消息位于组中;- 给String 设置格式属性;创建个体消息并将其放置到队列上;在组中的最后一条消息上设置messageFlags 属性,从而显示出消息是组中的最后一条;提交事务处理。import com.ibm.mq.*;public class GroupReceiver {private MQQueueManager qmgr;private MQQueue outQueue;private String queueName = "SAMPLE.QUEUE" ;private String host = "ITSOG" ;private String channel = "JAVA.CLIENT.CHNL" ;private String qmgrName = "ITSOG.QMGR1" ;private MQMessage outMsg;private MQGetMessageOptions pmo;public static void main (String args[]) {GroupReceiver gs = new GroupSender();gs.runGoupSender();}public void runGoupSender() {try {init();sendGroupMessages();qmgr.commit();System.out.println("\n Messages successfully Send " ) ;}catch (MQException mqe) {mqe.printStackTrace();try{System.out.println("\n Backing out Transaction " ) ;qmgr.backout();System.exit(2);}catch(Exception e) {e.printStackTrace();System.exit(2);} }catch(Exception e) {e.printStackTrace();System.exit(2);} }private void init() throws Exception {/设置MQEnvironment 属性以便客户机连接*/MQEnvironment.hostname = host ;MQEnvironment.channel = channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/qmgr = new MQQueueManager ( qmgrName);/*设置队列打开选项以便输出*/int opnOptn =MQC.MQOO_OUTPUT |MQC.MQOO_FAIL_IF_QUIESCING ;outQueue = qmgr.accessQueue ( queueName , opnOptn,null,null,null ) ;}private void getGroupMessages() throws Exception {/*设置放置消息选项*/pmo =new MQPutMessageOptions();pmo.options =pmo.options +MQC.MQPMO_LOGICAL_ORDER ;pmo.options =pmo.options +MQC.MQPMRF_GROUP_ID ;outMsg =new MQMessage();/*设置消息标记,表示该消息属于组*/outMsg.messageFlags =MQC.MQMF_MSG_IN_GROUP ; /*把消息格式设置成串*/outMsg.format =MQC.MQFMT_STRING ; String msgData =null;/*把10 个简单消息作为一组发送*/int i =10;while(i >0){msgData ="This is the "+i +"th message in the group ";outMsg.writeString(msgData);if (i ==1)outMsg.messageFlags =MQC.MQMF_LAST_MSG_IN_GROUP ; i--;/*每次放置一个消息到队列)*/outQueue.put(outMsg,pmo);/*清理缓冲区,以便重用*/outMsg.clearMessage();}} }12.5.6简单的组接收应用程序我们的下一个程序范例GroupReceiver.java 将讲解如何在组中获取消息。该应用程序将在组里(通过GroupSender 应用程序放置)获取消息,该组是以工作单位中作为组的队列。有关步骤如下:调入必需的包;为客户机连接设置MQEnvironment 属性;连接到队列管理器;设置队列打开选项以获得输入;打开队列以获得输入;设置放置消息选项;- 设置选项以便在同步点控制下获得消息;- 设置选项,当在组里提供所有消息时,以便只处理消息;- 设置选项以便以逻辑顺序处理信息;创建消息缓冲区;设置消息标题属性;创建个体消息并将其放置到队列上;从队列上获取消息直到处理完最后消息;在控制台上显示消息内容;提交事务处理。GroupReceiver.java例子应用程序import com.ibm.mq.*;public class GroupReceiver {private MQQueueManager qmgr;private MQQueue inQueue;private String queueName ="SAMPLE.QUEUE";private String host ="ITSOG";private String channel ="JAVA.CLIENT.CHNL";private String qmgrName ="ITSOG.QMGR1";private MQMessage inMsg;private MQGetMessageOptions gmo;public static void main (String args[]){GroupReceiver gs =new GroupReceiver();gs.runGoupReceiver();}public void runGoupReceiver() {try {init();getGroupMessages();qmgr.commit();System.out.println("\n Messages successfully Send ");}catch (MQException mqe){mqe.printStackTrace();try{System.out.println("\n Backing out Transaction ");qmgr.backout();System.exit(2);}catch(Exception e){e.printStackTrace();System.exit(2);} }catch(Exception e){e.printStackTrace();System.exit(2);} }private void init()throws Exception {/*为客户机连接设置MQEnvironment 属性*/MQEnvironment.hostname =host ;MQEnvironment.channel =channel ;MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,MQC.TRANSPORT_WEBSPHERE MQ);/*连接到队列管理器*/qmgr =new MQQueueManager (qmgrName);/*设置队列打开选项以输入*/int opnOptn =MQC.MQOO_INPUT_AS_Q_DEF |MQC.MQOO_FAIL_IF_QUIESCING ;/*打开队列以输入*/inQueue =qmgr.accessQueue (queueName ,opnOptn,null,null,null );}private void getGroupMessages()throws Exception {/*设置获取消息选项*/gmo =new MQGetMessageOptions();gmo.options =MQC.MQGMO_FAIL_IF_QUIESCING;gmo.options =gmo.options +MQC.MQGMO_SYNCPOINT ;/*等待消息*/gmo.options =gmo.options +MQC.MQGMO_WAIT ; /*设置等待时间限制*/gmo.waitInterval =5000 ; /*只获取消息*/gmo.options =gmo.options +MQC.MQGMO_ALL_MSGS_AVAILABLE ;         /*以逻辑顺序获取消息*/gmo.options =gmo.options +MQC.MQGMO_LOGICAL_ORDER ; gmo.matchOptions =MQC.MQMO_MATCH_GROUP_ID ;/*创建消息缓冲区*/inMsg =new MQMessage();String msgData =null;/*处理组消息*/while(true){inQueue.get(inMsg,gmo);int msgLength =inMsg.getMessageLength();msgData =inMsg.readString(msgLength);System.out.println("The message is \n "+msgData);char x =gmo.groupStatus ;/*检查看是否是最后消息标记*/if(x ==MQC.MQGS_LAST_MSG_IN_GROUP){System.out.println("B Last Msg in Group");break;}inMsg.clearMessage();} } }您如欲进行更深入的探讨,可参考《WebSphere MQ 发布/预订应用程序》,您可以从以下网址下载:http://www.ibm.com/redbooks。12.6本章小结本章介绍了如何利用WebSphere MQ for Java 编程。并且为那些希望编写与WebSphere MQ相连接的Java 应用程序或小程序的程序员提供所需的信息。WebSphere MQ Base Java可以使用Java applets、应用程序或servlets来调用和查询WebSphere MQ。在客户端机器上不用安装任何WebSphere MQ程序,直接通过WebSphere MQ for Java作为一个Internet终端用户就可以参与交易的执行。12.7本章练习1.使用WebSphere MQ Java API 编写文件的发送程序。2.使用WebSphere MQ Java API编写文件的接收程序。