GlassFish使用集成的MQ的相当简单,没有什么要配置的。但是要使用其他MQ产品,则需颇费一番功夫。下面详细介绍下GlasshFish中配置SonicMQ的过程。
软件信息: GlassFish3.1.1, SonicMQ 6.1.
ü 安装 Genericra
下载地址: http://genericjmsra.java.net/ (据说可以用UpdateTool 下载并安装,我用Update Tool找不到这个东西)
我下载了个最新的版本2.1,随笔放那里,假说C盘根目录吧。则按装方法为,
a. 运行cmd开命令行,并进入C盘根目录 (你的genericra.rar放的地方);
b. 运行asadmin (前提是你已经把 $glassFish/bin加入了Path中);
c. 然后敲入 deploy genericra.rar即可。
ü 建立Resource Adapter
我使用的命令行 (asadmin中),执行
create-resource-adapter-config --user admin --property SupportsXA=true:ProviderIntegrationMode=javabean:ConnectionFactoryClassName=com.sun.messaging.ConnectionFactory:\CommonSetterMethodName=setProperty:UserName=guest:Password=guest:\QueueConnectionFactoryClassName=com.sun.messaging.QueueConnectionFactory:\TopicConnectionFactoryClassName=com.sun.messaging.TopicConnectionFactory:\QueueClassName=com.sun.messaging.Queue:TopicClassName=com.sun.messaging.Topic:\LogLevel=info:UserName=guest:Password=guest:XAQueueConnectionFactoryClassName=com.sun.messaging.XAQueueConnectionFactory:\XATopicConnectionFactoryClassName=com.sun.messaging.XATopicConnectionFactory:\XAConnectionFactoryClassName=com.sun.messaging.XAConnectionFactory genericra
ü 建立连接池及连接工厂
create-connector-connection-pool --raname genericra --connectiondefinition javax.jms.QueueConnectionFactory qcpool
asadmin create-connector-resource --poolname qcpool jms/QCFactory
ü 创建Destination
asadmin create-admin-object --raname genericra --restype javax.jms.Queue --property DestinationProperties=Name\\=clientQueue jms/clientQueue
至此,配置已经差不多了了。 (其实这些官方网站都写的很清楚),到Admin控制台,大概就是这样,
接下来,我就直接在Admin Console中操作了,
一, 为qcpool指定MQ server的 Jndi信息,就是你的sonicMQ server的连接信息。其中
JndiProperties = java.naming.factory.initial=com.sonicsw.jndi.mfcontext.MFContextFactory,java.naming.provider.url=tcp://192.168.0.125:2506,com.sonicsw.jndi.mfcontext.domain=Domain1,java.naming.security.principal=Administrator,java.naming.security.credentials=Administrator
二,把Sonic MQ相关的包放到$glassFish/lib中去,
至此你已经可以往SonicMQ发消息了,比较让人振奋了。代码如下,
package com.apress.ejb3.chapter02; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.*; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.Session; /** * Session Bean implementation class MessageSender */ @Stateless(name="MessageSender", mappedName="ejb/MessageSender") public class MessageSender implements MessageSenderRemote, MessageSenderLocal { @Resource(mappedName = "jms/QCFactory") private QueueConnectionFactory newGradeConnectionFactory; @Resource(mappedName = "jms/clientQueue") private Queue queue; /** * Default constructor. */ public MessageSender() { } public String sendMessage(String txtmsg){ System.out.println("Start to sendMessage."); QueueConnection connect = null; try { // create a session for use in this thread/transaction connect = newGradeConnectionFactory.createQueueConnection(); QueueSession session = connect.createQueueSession(true, 10); // // create a new message // QueueSender sender = session.createSender(queue); Message msg = session.createTextMessage(txtmsg); // return newGradeQueue.get?QueueName(); sender.send(msg); // session.commit(); } catch (Throwable je) { je.printStackTrace(); // throw a more friendly exception } finally { if (connect != null) { try { connect.close(); } catch (Exception e) { } } } return "successfully"; } }
但用MDB收消息是否也可以了呢?结果是不行的。并且MDB不能这用Annotation,必须要使用xml去配置。配置文件如下,
DemoDataRequestProcessor genericra ConnectionFactoryJndiName jms/QCFactory DestinationJndiName jms/clientQueue destinationType javax.jms.Queue
你的MDB理论上可以工作了,测试代码如下,
package sonicMQ.testing; import javax.ejb.MessageDriven; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; /** * Message-Driven Bean implementation class for: DemoDataRequestProcessor * */ @MessageDriven(name="DemoDataRequestProcessor",mappedName="jms/clientQueue") @TransactionManagement(value= TransactionManagementType.BEAN) public class DemoDataRequestProcessor implements MessageListener { /** * Default constructor. */ public DemoDataRequestProcessor() { // TODO Auto-generated constructor stub } /** * @see MessageListener#onMessage(Message) */ public void onMessage(Message message) { try { if (message instanceof TextMessage) { TextMessage orderMessage = (TextMessage) message; System.out.println("DemoDataRequestProcessor recieved = " + orderMessage.getText()); } else { System.out.println("Invalid message "); } } catch (Exception ex) { ex.printStackTrace(); } } }
但是我这边,总是抛异常,如下
java.lang.ClassCastException: com.sun.genericra.outbound.SessionAdapter cannot be cast to progress.message.jimpl.Session at progress.message.jimpl.aspi.wd.handleMessage(Unknown Source) at progress.message.zclient.MessageHandler.doNextWorkItem(Unknown Source) at progress.message.zclient.lx.threadMain(Unknown Source) at progress.message.zclient.DebugThread.run(Unknown Source)
无赖之下,我不得不研究了下genericra的相关代码,最终改了两个类,改的比较下;
InboundJmsResource的set方法,改动后如下,
SessionAdapter加了个getPhysicalSession方法,如下
两个java文件也加加附件中了。
至此,MDB终于也可以工作了。虽然其中走了很多弯路,没一个小小的细节搞明白都包含了N次失败的尝试,最终终于完成了,当然其间也了解很多其它与此不相关的东西。
----------------------------------------------------------------------
张瑜,Mybeautiful, [email protected].