本文主要在讲述BEA WebLogic Server8.1 JMS和Messaging Bridge的基本概念及其优势的基础上,并图文并茂的讲解BEA WebLogic Server8.1 JMS与第三方消息中间件IBM MQSeries5.2 进行事务性消息转发的集成方案。IBM MQSeries的基本概念也将被涉及。
关键字:WebLogic Server,JMS,MQSeries,连接工厂, JMS服务器,Messaging Bridge,队列,队列管理器,通道,消息驱动Bean
How to user messageing bridge in BEA WebLogic Sever8.1 to transfer messages transactionally between BEA WebLogic Sever8.1 Queues and IBM MQSeries Queues?
In this paper,we will desribe the BEA WebLogic Sever8.1 JMS and Messaging Bridge concept and their benefits.On this base,we will graphicly and literally demonstrate how to set up messaging bridges to transfer messages transactionally between BEA WebLogic Sever8.1 Queues and IBM MQSeries Queues.Also,the IBM MQSeries concept will be touched.
Key words: WebLogic Server,JMS,MQSeries,Connection Factory, JMS Server,Messaging Bridge,Queue,QueueManager,Channel,MDB
1 基础知识简介
1.1 JMS简介
1.2 Messaging Bridge简介
1.3 IBM MQSeries简介
2 事务性集成方案简介
2.1 方案概览
2.2 前期准备
3 配置MQ
3.1 配置队列管理器
3.2 配置服务器连接通道
3.3 配置队列
3.4 绑定JMS对象
4 配置WebLogic
4.1 创建Server域
4.2 修改启动文件
4.3 部署JCA适配器
4.4 配置JMS
4.5 配置Messaging Bridge
5 设计Messaging Bridge应用程序
5.1 设计消息发送端
5.2 设计消息接收端
5.3 部署MDB
6 测试Messaging Bridge
6.1 测试WLS2MQBridge
6.2 测试MQ2WLSBridge
7 另辟蹊径
8 问题
9 总结
JMS(Java Message Service)是访问企业消息系统的标准API,它便于消息系
统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
WebLogic Server包含一个完整的、有丰富特性的消息服务器。第三方的消息服务器(如IBM MQSeries),只要其提供了JMS API的实现,也可以在WebLogic Server中运行。想了解更为详细的JMS基础知识可以参考文章BEA WebLogic Server8.1 JMS入门。
什么是Messaging Bridge呢?它是一种由WebLogic Server提供的J2EE设备,用于转发两个消息提供者的消息。你可以使用Messaging Bridge将消息从一个消息提供者的目的地(队列或者主题)移至另外一个消息提供者的目的地。因此,当WegLogic应用程序需要与第三方消息提供者(比如IBM MQSeries)进行交互时,Messaging Bridge就可以承担这个中间角色。
Messaging Bridge具有如下优点:
不需要编码,纯配置,加速你的开发;
灵活的体系结构,容易配置多个Messaging Bridges,并且而且可以动态的启动和停止单个Messaging Bridge;
采用即取即用的MQ 适配器,实现全面的MQ JMS 支持,能够设定MQ 主题查询;
充分利用WebLogic容器进行服务管理,并且集中所有的Bridges资源在一个线程池;
全面的事务处理能力,两阶段事务处理;
全面的JCA 支持;
确保服务质量和连接管理,实实在在的一次性服务;
控制台监视能力;
集成BEA WebLogic应用与外部消息提供商,以便将新的应用与现有的
投资连接起来。
IBM MQSeries是IBM的商业通讯中间件(Commercial Messaging Middleware)。IBM MQSeries提供一个具有工业标准,安全,可靠的信息传输系统。它的功能是控制和管理一个集成的商业应用,使得组成这个商业应用的多个分支程序(模块)之间通过传递信息完成整个工作流程。IBM MQSeries具有特殊的技术防止信息重复传送,确保信息一次且仅一次(once-and-only-once)传递,保证传输的可靠性。本文使用的MQ版本为IBM MQSeries 5.2。
了解完JMS,Messaging Bridge和MQ的基本概念后,让我们看看是怎么使用Messaging Bridge,实现WebLogic Server8.1 JMS和IBM MQSeries5.2的事务性集成方案的。
我们的目标是实现WebLogic Server8.1和IBM MQSeries5.2之间的事务性消息转发:包括WebLogic Server8.1消息转发给IBM MQSeries5.2,以及IBM MQSeries5.2消息转发给WebLogic Server8.1。具体地,将WebLogic Server8.1队列WLSSendQueue的消息转发到IBM MQSeries5.2队列MQReceiveQueue,同时将IBM MQSeries5.2队列MQSendQueue的消息转发到WebLogic Server8.1队列WLSSendQueue。
我们需要做如下配置,下图为方案的体系结构:
Messaging Bridge通过WebLogic Server提供的J2EE Connector Architecture JMS Adapter(J2EE连接器体系结构——JMS适配器)与WebLogic JMS队列连接,同时Messaging Bridge也是通过WebLogic Server提供的J2EE Connector Architecture JMS Adapter与MQ队列连接。
Messaging Bridge服务质量等级有三种:Exactly-Once, Almost-Once,Duplicate-Okey。三者可靠性依次降低,根据不同服务质量等级,WebLogic Server8.1提供有四种JMS JCA适配器:
jms-xa-adp.rar: Exactly-Once(仅一次)
jms-notran-adp.rar: Almost-Once(至多一次)或者Duplicate-Okey(至少一次)
jms-local-adp.rar: Duplicate-Okey(至少一次),不常用
jms-notran-adp51.rar: 与WebLogic Server 5.1的JMS交互,与jms-notran-adp.rar类似。
方案要求实现事务性消息转发,所以我们必须让Messaging Bridge提供Exactly-Once 的服务质量。JMS JCA适配器使用MQ JMSAdmin工具产生的JNDI对象来连接MQ队列,为了提供Exactly-Once的服务质量,JMS JCA适配器必须使用MQXAQueueConnectionFactory JNDI对象来与MQ连接。可是MQ JMSAdmin工具仅支持在binding模式(绑定模式)下产生MQXAQueueConnectionFactory JNDI对象。MQ JMS驱动器在client模式(客户端模式)下并不支持分布式事务。而在绑定模式下,MQ采用文件系统来绑定对象,必须是本机才能访问。
因此,为了让Messaging Bridge提供Exactly-Once 的服务质量,WebLogic Server8.1和MQ必须运行在同一台机器上。假如Exactly-Once的服务质量不是必须的,MQSeries可以和WebLogic Server运行在不同的机器上。
在继续我们的方案讨论之前,我们需要在Windows2000操作系统下安装下列软件:
安装BEA WebLogic Server8.1的详细步骤请参考BEA dev2dev学堂文章:跟我学WebLogic Server之一 --如何安装BEA WebLogic Server。
安装IBM MQSeries5.2 Windows2000版本,注意:MQ安装目录(C:MQSeries)最好自定义,且不含空格。安装完成后,可以用明信片的例子验证安装正确性。相关软件可以到以下链接下载:http://www.ibm.com/software/ts/mqseries/downloads。
安装MQSeries classes for Java和MQSeries classes for Java Message Service 以提供JMS驱动,使用JMSAdmin工具,注意:安装目录(C:MQSeriesJava)最好与MQSeries的安装目录一致。相关软件可以到以下链接下载:http://www.ibm.com/software/ts/mqseries/txppacs/ma88.html。
安装MQSeries SupportPac MA0C以支持Topic,支持发布/订阅模式,本文可以略过。相关软件可以到以下链接下载:http://www.ibm.com/software/ts/mqseries/txppacs/ma0c.html。
首先,确认MQ已经启动。如果MQ没有启动,则通过控制面板/管理工具/服务启动IBM MQSeries服务。
MQ的配置有两个方式:一种是采用MQ资源管理器;另一种是采用MQ命令行。在MQ资源管理器中配置,简单直观,由于本文并不着重研究MQ,因此采用MQ资源管理器的方式配置MQ资源。
创建队列管理器可以使用MQ资源管理器,也可以使用MQ基本操作命令:crtmqm -q QM_TestBridge,其中-q是指创建缺省的队列管理器。为简单直观起见我们采用MQ资源管理器来创建队列管理器:
按照创建本地队列MQReceiveQueue的做法,创建本地队列MQSendQueue。
使用MQ JMSAdmin命令行工具生成被管理的JMS对象。在安装了MQSeries Client for Java之后,在%MQ_JAVA_INSTALL_PATH%/in目录下找到JMSAdmin.config文件。该文件主要用来说明Context的存储方式及存储地址,对应于文件中的两个参数INITIAL_CONTEXT_FACTORY和PROVIDER_URL。典型的JMSAdmin.config文件内容如下:
#INITIAL_CONTEXT_FACTORY=com.sun.jndi.ldap.LdapCtxFactoryINITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory#INITIAL_CONTEXT_FACTORY=com.ibm.ejs.ns.jndi.CNInitialContextFactory##PROVIDER_URL=ldap://polaris/o=ibm,c=usPROVIDER_URL=file:/d:/temp#PROVIDER_URL=iiop://localhost/#SECURITY_AUTHENTICATION=none
INITIAL_CONTEXT_FACTORY表示JMSAdmin Tool使用的服务提供商。当前有三种受支持的值。com.sun.jndi.ldap.LdapCtxFactory用于LDAP,如果使用它就必须安装一个LDAP服务器。com.sun.jndi.fscontext.RefFSContextFactory用于文件系统上下文,它只需要使用者提供存放上下文的文件路径。com.ibm.ejs.ns.jndi.CNInitialContextFactory是专门为websphere提供的,它需要和websphere的CosNaming资源库一起使用。
PROVIDER_URL表示会话初始上下文的URL,由JMSAdmin tool实现的所有JNDI操作的根。它和INITIAL_CONTEXT_FACTORY一一对应:
ldap://hostname/contextname 用于LDAP;
file:[drive:]/pathname 用于文件系统上下文;
iiop://hostname[:port]/[?TargetContext=ctx] 用于访问websphere CosNaming名称空间。
最后还有一个参数SECURITY_AUTHENTICATION,用于说明JNDI是否把安全性凭证传递给了您使用的服务供应商。只有当使用了LDAP服务供应商时,才使用此参数。此参数有三个值,none(匿名认证)、simple(简单认证)和CRAM-MD5认证机制。如果没有提供有效值,缺省值为none。
在使用MQ JMSAdmin命令行工具之前,我们应该使用我们自己的配置文件来运行JMSAdmin。JMSAdmin.config位于%MQ_JAVA_INSTALL_PATH%/bin目录下,备份JMSAdmin.config文件到新建目录bridgeconfig下,然后修改这个文件的三个变量值:
INITIAL_CONTEXT_FACTORY使用文件系统上下文:
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory
PROVIDER_URL为任意的文件目录,文件名不能包含空格
PROVIDER_URL=file:/C:/mqseries/JNDI
安全授权为NONE
SECURITY_AUTHENTICATION=none
备份%MQ_JAVA_INSTALL_PATH%/bin目录下的jmsadmin.bat文件,修改jmsadmin.bat。这个文件用来启动JMSAdmin工具,我们需要将ibm类包包含在类路径下:
set MQ_JAVA_INSTALL_PATH=C: MQSeriesjavaset MQ_JAVA_LIB=%MQ_JAVA_INSTALL_PATH%libset MQ_CLASSPATH=%MQ_JAVA_LIB%com.ibm.mq.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%com.ibm.mqbind.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%com.ibm.mqjms.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%fscontext.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%jms.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%jta.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%ldap.jarset MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%providerutil.jar
修改后的JMSAdmin.bat文件如下图所示:
使用刚刚自定义的配置文件,启动JMSAdmin工具:到%MQ_JAVA_INSTALL_PATH%/bin下,运行命令:jmsadmin -cfg ./ridgeconfigjmsadmin.config。
在新窗口出现InitCtx命令提示,表明已经开始一个MQSeries JMSAdmin 会话。使用dis ctx命令查询已经存在的被管理的JNDI 对象,可以看到目前并没有对象。
生成一个MQXAQueueConnectionFactory对象,Messaging Bridge将使用这个工厂对象建立MQ的XA连接,使用命令DEFINE XAQCF,起名:bridge.mqQCFXA。
使用DEFINE Q命令,生成JMSQueue对象来绑定MQ队列MQReceiveQueue。
同理,使用DEFINE Q命令,生成JMSQueue对象来绑定MQ队列MQSendQueue。
再次使用dis ctx命令,查看目前已有的对象和绑定,可以看到XA连接工厂和队列都已绑定。注意到,我们在绑定队列并没有指明队列的队列管理器名称,是因为我们队列对应的队列管理器是默认的队列管理器。否则我们需要使用下面的命令来绑定队列:DEFINE Q(jndiName) QUEUE(qName) QMGR(qMName)。
确认后,用END命令退出JMSAdmin工具。
创建Server Domain(domain名称:mydomain),假如已经有了,就不用创建了,建议采用开发模式(默认配置)。具体的创建步骤请参考:
http://e-docs.bea.com/platform/docs81/confgwiz/tutorials.html#1055856
修改WebLogic的启动文件startWebLogic.cmd。将IBM MQSeries和IBM MQSeries Java的安装目录加到WebLogic path下,同时将MQ JMS Java类包加入到WebLogic classpath下:
@rem added the following to configure messaging bridge with local MQSeries installation@set MQ_INSTALL_PATH=C:MQSeries@set MQ_JAVA_INSTALL_PATH=C:MQSeriesjava@set MQ_JAVA_LIB=%MQ_JAVA_INSTALL_PATH%lib@set MQ_CLASSPATH=%MQ_JAVA_LIB%com.ibm.mq.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%com.ibm.mqbind.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%com.ibm.mqjms.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%fscontext.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%jms.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%jndi.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%jta.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%ldap.jar@set MQ_CLASSPATH=%MQ_CLASSPATH%;%MQ_JAVA_LIB%providerutil.jar@set MQ_PATH=%MQ_INSTALL_PATH%/in;%MQ_JAVA_INSTALL_PATH%/in;%MQ_JAVA_INSTALL_PATH%lib@set PATH=%MQ_PATH%;%PATH%@setCLASSPATH=%MQ_CLASSPATH%;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%jrelib t.jar;%WL_HOME%serverlibwebservices.jar;%CLASSPATH%
修改启动文件后,将JCA适配器包%BEA_HOME%weblogic81serverlibjms-xa-adp.rar复制到域mydomainapplicaions目录下,启动WebLogic Server8.1,由于采用开发模式,适配器将自动部署。在生产环境下,需要通过Console将jms-xa-adp.rar 发布到WebLogic Server上。
JMS的配置比较简单,这里不再详细介绍。详细的JMS配置可以参考BEA dev2dev学堂文章BEA WebLogic Server8.1 JMS入门。
启动WebLogic Server8.1,在Console创建支持XA的连接工厂WLSCFXA,JNDI Name为bridge.wlsCFXA。
创建文件后备存储BridgeFileStore和目录Directionary为 %%BEA_HOME%user_projectsdomainsmydomain/ridgefilestore(务必事先创建该目录)。
4.4.3 创建JMS服务器
创建JMS服务器BridgeJMSServer和Paging Store设为" BridgeFileStore" 。
在JMS服务器BridgeJMSServer下,创建JMS发送队列WLSSendQueue,JNDI名称为bridge.wlsSendQueue。
同理,在JMS服务器BridgeJMSServer下,创建JMS接收队列WLSReceiveQueue,JNDI名称为bridge.wlsReceiveQueue。
同理,克隆WLSSendBridgeDestination,重命名为WLSReceiveBridgeDestination,Connection Factory JNDI Name为bridge.wlsCFXA, Destination JNDI Name为bridge.wlsReceiveQueue。
同理,克隆MQSendBridgeDestination,重命名为MQReceiveBridgeDestination,Connection Factory JNDI Name为bridge.mqQCFXA, Destination JNDI Name为bridge. mqReceiveQueue。
克隆WLS2MQBridge,重命名为MQ2WLSBridge,Source Bridge Destination为MQSendBridgeDestination和Target Bridge Destination为WLSReceiveBridgeDestination。
创建完Messaging Bridge WLS2MQBridge和MQ2WLSBridge之后,确认MQ和队列管理器都是启动状态,点击"myserver"节点,点击"Service"标签,再点击"Bridge"标签,点击"Monitor all Messaging Bridge Runtimes..."链接,查看Messaging Bridge的运行情况,同时也可以在此设置Messaging Bridge Thread Pool Size的大小。看到WLS2MQBridge和MQ2WLSBridge的State :Active,标识WLS2MQBridge和MQ2WLSBridge工作正常。
通过上面的MQ和WebLogic的配置,我们可以用一个普遍的应用程序来验证配置的正确性:设计一个Java应用程序,发送消息至WebLogic发送队列WLSSendQueue,用一个MDB监听MQ接收队列MQReceiveQueue,即时接收消息。同理,发送消息至MQ发送队列MQSendQueue,用一个MDB监听WebLogic接收队列WLSReceiveQueue,即时接收消息
设计Java客户端向发送队列WLSSendQueue(MQSendQueue)发送测试消息,正如我们方案要求的一样:事务性要求,采用XA事务。所以连接工厂必须使用支持XA的XAQueueConnectionFactory,并且采用JTA的UserTrancation和1PC方式。在实际应用中可以在事务加入其他的XA资源,自动变成2PC。这里通过lookup的方式获取UserTrancation对象,如果客户端在WebLogic环境下,可以直接调用类weblogic.transaction.TxHelper的静态方法getUserTransaction()获取UserTrancation对象。
该发送程序的发送队列的JNDI名称、连接工厂JNDI名称、会话初始化上下文以及事务JNDI对象的URL(这里为WebLogic服务器的URL)都是通过main函数的输入参数传递的。输入参数依次为:事务JNDI对象的URL、JMS 资源JNDI树的URL、INITIAL_CONTEXT_FACTORY、发送队列的JNDI名称、连接工厂JNDI名称。通过传人不同的队列JNDI名称和会话初始化上下文,这个类可以支持往MQ发送队列里发送测试消息或者往WebLogic发送队列里发送测试消息。
package messagebridge;import java.util.Hashtable;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.jms.JMSException;import javax.jms.Queue;import javax.jms.XAQueueConnection;import javax.jms.XAQueueConnectionFactory;import javax.jms.QueueSender;import javax.jms.QueueSession;import javax.jms.Session;import javax.jms.TextMessage;import javax.transaction.UserTransaction;import javax.transaction.NotSupportedException;import javax.transaction.RollbackException;import javax.transaction.SystemException;import javax.transaction.HeuristicMixedException;import javax.transaction.HeuristicRollbackException;public class SendMessageTest {private InitialContext ctx = null;private InitialContext ctxTX = null;private Queue queue = null;private XAQueueConnection connection = null;private XAQueueConnectionFactory factory = null;private QueueSender queueSender = null;private QueueSession session = null;private UserTransaction ut = null;public static void main(String[] args) {SendMessageTest smg = new SendMessageTest();smg.test(args);}public void test(String[] args) {try {if (args.length<5){System.out.print("发送程序使用不当!");return;}String wlsurl=args[0];String init=args[1];String url=args[2];String cf=args[3];String q=args[4];// Get the initial contextHashtable env = new Hashtable();env.put(Context.INITIAL_CONTEXT_FACTORY,init);env.put(Context.PROVIDER_URL, url);ctx = new InitialContext(env);Hashtable envTX = new Hashtable();envTX.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");envTX.put(Context.PROVIDER_URL, wlsurl);ctxTX = new InitialContext(envTX);ut = (UserTransaction) ctxTX.lookup("javax.transaction.UserTransaction");factory = (XAQueueConnectionFactory) ctx.lookup(cf);connection = factory.createXAQueueConnection();session = connection.createXAQueueSession().getQueueSession();queue = (Queue) ctx.lookup(q);connection.start();queueSender = session.createSender(queue);TextMessage msg = session.createTextMessage();msg.setText("Send test message.");ut.begin();queueSender.send(msg);ut.commit(); // 1PCSystem.out.println("Sended: " + msg.getText());}catch (NamingException e) {System.out.println("NamingException:" + e.getMessage());}catch (JMSException e) {System.out.println("JMSException:" + e.getMessage());}catch (NotSupportedException e) {System.out.println("NotSupportedException:" + e.getMessage());}catch (SystemException e) {try {ut.rollback();}catch (Exception e1) {}System.out.println("SystemException:" + e.getMessage());}catch (HeuristicRollbackException e) {try {ut.rollback();}catch (Exception e1) {}System.out.println("HeuristicRollbackException:" + e.getMessage());}catch (HeuristicMixedException e) {try {ut.rollback();}catch (Exception e1) {}System.out.println("HeuristicMixedException:" + e.getMessage());}catch (RollbackException e) {try {ut.rollback();}catch (Exception e1) {}System.out.println("RollbackException:" + e.getMessage());}finally {try {ctx.close();}catch (Exception e) {}try {ctxTX.close();}catch (Exception e) {}cleanup();}}private void cleanup() {try {queueSender.close();session.close();connection.close();}catch (Exception e) {e.printStackTrace();}}}
设计MDB消息接收端即时接收队列WLSReceiveQueue(MQReceiveQueue)的消息。设计MDB非常简单,无论是采用JBuilder还是Workshop,都只需要设计一个实现接口MessageDrivenBean, MessageListener的类,该类实现onMessage()方法。值得注意的是在Workshop中开发EJB采用EJBGen的方式,采用填充式代码,使得业务方法实现和相关配置都非常的简单和直观。
在这里我们设置MDB的事务类型为CMT,事务属性为Required,以保证整个发送接收消息的QoS都是Exactly-once。同时设置pool size的初始大小为2,最大为8,而destination-jndi-name,connection-factory-jndi-name,provider-url,connection-factory-jndi-name根据需要进行设置,这里有两种情况,一个是监听WebLogic队列WLSReceiveQueue,另一个是监听MQ队列MQReceiveQueue。
设计完之后,将MDB应用打包为MessageBridge.jar,最简单的方式是采用JBuilder或者Workshop的build应用功能自动打包,你可以采用WebLogic的EJB打包命令打包,注意在WebLogic不同版本下打包命令并不一样。
最后,采用WebLogic Builder验证一下包的正确性。
package messagebridge;import javax.ejb.*;import javax.jms.*;import javax.naming.*;public class MessageBridgeBeanimplements MessageDrivenBean, MessageListener {MessageDrivenContext messageDrivenContext;public void ejbCreate() throws CreateException {/**@todo Complete this method*/}public void ejbRemove() {/**@todo Complete this method*/}public void onMessage(Message msg) {//do your businesstry {if (msg == null || ! (msg instanceof TextMessage)) {System.out.println(msg.toString());}else {TextMessage textMsg = (TextMessage) msg;System.out.println("Receive Message:" + textMsg.getText());}}catch (Exception e) {System.err.println(e.toString());e.printStackTrace();}}public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) {this.messageDrivenContext = messageDrivenContext;}}
你可以采用类似部署JMS适配器的方式部署MDB应用MessageBridge.jar。这里为了简单起见,在开发模式下(启动文件startWebLogic.cmd: set PRODUCTION_MODE=false或者set PRODUCTION_MODE=),直接将MessageBridge.jar拷贝到%DOMAIN_NAME%/applications下,应用将自动部署。
首先确保WebLogic Server8.1和MQ已启动,运行发送消息客户端SendMessageTest.class,使用命令为:java messageBridge.SendMessageTest t3://localhost:80 weblogic.jndi.WLInitialContextFactory t3:// localhost:80 bridge.wlsCFXA bridge.wlsSendQueue,将消息发送到队列WLSSendQueue。运行结束后,提示Sended:Send test message.,表示测试消息Send test message.成功发送至发送队列WLSSendQueue。
注意:运行发送消息客户端的classpath必须包含weblogic.jar,以便进行JNDI对象的查找。
客户端发送测试消息Send test message.后,我们可以采用以下三种方式来接收消息:
使用MQ命令:amqsget MQReceiveQueue QM_TestBridge(队列管理器的名字可以不带),可以取出MQReceiveQueue的消息。
注意:该命令必须在%MQ_INSTALL_PATH%/in目录下运行。
这时MDB MessageBridge的监听队列必须设置为MQReceiveQueue,具体配置如下:
<destination-jndi-name>bridge.mqReceiveQueue</destination-jndi-name> <initial-context-factory>com.sun.jndi.fscontext.RefFSContextFactory</initial-context-factory><provider-url>file:/C:/MQSeries/JNDI</provider-url><connection-factory-jndi-name>bridge.mqQCFXA</connection-factory-jndi-name>
客户端发送测试消息后,紧接着在WebLogic命令窗口可以看到MDB已成功接收消息:Receive Message:Send test message.。
这就证实了消息Send test message.通过Messaging Bridge WLS2MQBridge从发送队列WLSSendQueue转发到接收队列MQReceiveQueue。
注意:一旦使用MQ命令取出消息后,MDB就无法接收到消息。同理,一旦使用MDB接收消息后,使用MQ资源管理器无法查看消息,使用MQ命令无法取出消息,因为消息已被接收。
从MQ队列MQSendQueue发送消息的方法有三种,我们可以选择其一:
运行发送消息客户端SendMessageTest.class,使用命令为:java messageBridge.SendMessageTest t3://localhost:80 com.sun.jndi.fscontext.RefFSContextFactory file:/C:/MQSeries/JNDI jmsbridge.mqQCFXA bridge.mqSendQueue,将消息发送到队列MQSendQueue。运行结束后,提示Sended:Send test message.,表示测试消息Send test message.成功发送至发送队列MQSendQueue。
注意:运行发送消息客户端的classpath必须包含weblogic.jar和MQ JMS类包,因为我们这里需要使用MQ JMS类和javax.transaction.UserTransaction。
使用MQ命令:amqsput MQSendQueue QM_TestBridge(队列管理器的名字可以不带),可以往队列MQSendQueue里放置消息。
注意:该命令必须在%MQ_INSTALL_PATH%/in目录下运行。
通过监控WebLogic队列WLSReceiveQueue,可以看到Messages Received为1。具体操作如下:点击导航栏"WLSReceiveQueue"子节点,在Console右边的窗口中点击标签"Monitoring",在点击超链接"Monitor all Active JMS Destinations..."。
这时MDB MessageBridge的监听队列必须设置为WLSReceiveQueue,具体配置如下:
<destination-jndi-name>bridge.wlsReceiveQueue</destination-jndi-name>
<connection-factory-jndi-name>bridge.wlsCFXA</connection-factory-jndi-name>
客户端发送测试消息后,紧接着在WebLogic命令窗口可以看到MDB已成功接收消息:Receive Message:Send test message.。
这就证实了消息Send test message.通过Messaging Bridge MQ2WLSBridge从发送队列MQSendQueue转发到接收队列WLSReceiveQueue。
对于WebLogic应用程序消费MQ队列消息的情况,更简单的做法是,直接采用MDB监听MQ队列。部署在WebLogic Server中的MDB能提供与Message Bridge同样的质量服务。使用XA事务处理,MDB支持Exactly-Once(仅一次)发送模式。若使用AUTO_ACKNOWLEDGE或者DUPS_OK_ACKNOWLEDGE确认模式,用户可以使用Duplicate-Okey(至少一次)发送模式。在这两种确认模式间的切换确实可以降低消息重复的机会的提高性能。若使用WebLogic JMS特有的NO_ACKNOWLEDGE或者MULTICAST_NO_ACKNOWLEDGE模式,则可以使用Almost-Once (至多一次)消息发送模式。如果连接失败,例如MQ重新启动,MDB还支持自动重新连接到MQ。同时,可以利用weblogic-ejb-jar.xml部署描述文件中的jms-polling-interval-seconds元素,还可以调整MDB连接失败后重新连接的轮询间隔。它的默认值是每10秒连接一次。
此外,当事务与没有实现WebLogic.jms.extensions.MDBTransaction接口的外
部JMS提供商(MQ)一起使用时,WebLogic Server还提供一种可配置机制,在连续出现一定数量的错误后,暂停MDB消息的接收。默认状态下,如果MDB碰到10次连续的错误,WebLogic Server MDB会暂停消息处理5秒钟。至于是何种错误,则由MDB调用setRollbackOnly()方法或者弹出RuntimeException消息定义。在WebLogic启动文件设定以下的Java系统属性,可调节连续出错的次数和休眠时间:weblogic.ejb20.MaxMDBErrors,这个属性控制消息驱动Bean的处理暂停前,连续出错的次数。每一个MDB部署都有一个独立的计数器,它在消息每次成功处理后重置。weblogic.ejb20.MDBErrorSleepTime,这个属性规定连续碰到weblogic.ejb20.MaxMDBErrors次错误后,消息驱动Bean暂停处理的时间(单位为秒)。
为了调试MDB与MQ的有关连接问题,不妨在WebLogic启动文件设定java属性weblogic.ejb.jms.connect.verbose和weblogic.ejb.jms.connect.debug为true(在7.0版本中,这种属性为weblogic.ejb20.jms.connect.verbose和weblogic.ejb20.jms.connect.debug)。
经过前面的介绍,相信读者对WebLogic Messaging Bridge和MQ都有一个大概的了解。本文采用了两个Messaging Bridge来实现WebLogic和MQ之间的消息转发。试问一下,假如怎么将MQ队列MQSendQueue消息转发到MQ队列MQReceiveQueue中?同样,如何将WebLogic队列WLSSendQueue消息转发到WebLogic队列WLSReceiveQueue中?
欢迎有兴趣的人士来信讨论:[email protected]。
本文首先论述了WebLogic Messaging Bridge的体系结构及其优点,然后着重介绍了BEA WebLogic Server8.1 JMS与第三方消息中间件IBM MQ Series5.2 进行事务性消息转发的集成方案:如何创建MQ队列;如何使用MQ JMSAdmin工具来生成被管理的对应MQ队列的JMS对象;如何在WebLogic里配置Messaging Bridge;如何使用Messaging Bridge在WebLogic与MQ之间进行事务性消息转发;以及如何设计应用程序测试和验证这些配置。
由于MQ的一些局限,比如在客户端模式下不支持分布式事务,本方案只能在单个机器实现。值得注意的是,本文的集成方案不仅适应于WebLogic与MQ的集成,对于其他第三方消息中间件的实现同样提出了普遍性的方案。所以除了MQ的具体配置外,本方案是普遍的WebLogic JMS与第三方消息中间件集成方案。