我正在研究可以被描述为自定义 WMQ 消息路由器/转发器的东西。目前,我在处理通过 MQ 发送的 JMS 消息时遇到了一些非常令人困惑的问题。我能够通过 JMS(使用 MQ 作为传输)接收从 Java 应用程序发送的消息,但我无法将消息发送到在 JMS 端点上侦听的 Java 应用程序。
我有一个测试 servlet 和消息驱动 bean - 两者都托管在 WebSphere Application Server 7.0 中(WebSphere MQ 7.0 用于消息传输)。Servlet 能够与 bean 通信,但如果我将转发器放在它们之间(通过重新配置 servlet 以与转发器通信,转发器将重建消息并将它们转发到 bean),bean 将无法处理请求。我在 WAS 日志中有这个错误:
[8/2/12 14:38:51:359 CEST] 00000031 SibMessage W [:] CWSJY0003W: JMSCC0110: An exception '
Message : java.lang.NullPointerException
Class : class java.lang.NullPointerException
Stack : com.ibm.msg.client.wmq.internal.messages.WMQMessageBase._parseMcdFolder(WMQMessageBase.java:445)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.constructProviderMessageFromRFH2(WMQReceiveMarshal.java:341)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.createProviderMessage(WMQReceiveMarshal.java:447)
: com.ibm.msg.client.wmq.internal.messages.WMQReceiveMarshal.exportProviderMessage(WMQReceiveMarshal.java:607)
: com.ibm.msg.client.wmq.internal.WMQConsumerShadow.getMsg(WMQConsumerShadow.java:1115)
: com.ibm.msg.client.wmq.internal.WMQSyncConsumerShadow.receive(WMQSyncConsumerShadow.java:334)
: com.ibm.msg.client.wmq.internal.WMQSession.loadMessageReference(WMQSession.java:1082)
: com.ibm.msg.client.jms.internal.JmsSessionImpl.consume(JmsSessionImpl.java:2847)
: com.ibm.msg.client.jms.internal.JmsSessionImpl.run(JmsSessionImpl.java:2549)
: com.ibm.mq.jms.MQSession.run(MQSession.java:860)
: com.ibm.mq.connector.inbound.WorkImpl.run(WorkImpl.java:172)
: com.ibm.ejs.j2c.work.WorkProxy.run(WorkProxy.java:399)
: com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1604)
[8/2/12 14:38:51:781 CEST] 00000031 SibMessage W [:] CWSJY0003W: MQJCA4004: Message delivery to an MDB 'XXX' failed with exception: 'null'
出现此错误后,消息端点会自动暂停。
我使用 RFHUtils 来获取 JMS 和我的应用程序发送的消息并比较它们 - UI 没有真正的区别(除了不同的传递模式,但这是另一回事)但是当我将消息保存到文件并比较它们时,我看到了这种差异(只是第一个 RFH2 文件夹):
通过 JMS 直接发送:
<mcd><Msd>jms_text</Msd></mcd>
通过我的应用发送:
<mcd><Msd dt="string" >jms_text</Msd></mcd>
RFH2 中的所有元素也包含类型。文件夹中的元素jms
顺序不同,但根据例外情况,问题应直接与mcd
文件夹有关。我不确定如何更好地诊断问题 - 我尝试为 JMS 配置跟踪,但我不知道如何为 WAS 执行此操作(我在星期二第一次使用 WAS)。标准 MQ 跟踪不提供更多信息。
我的 .NET 代码(使用 MQ 客户端 7.5 - amqmdnet.dll 7.5.0.0 的 WMQ API)非常复杂,但通常会:
接收者
- 在访问时
MQMessage
通过标准Get
调用接收消息(无特殊获取选项)MQQueue
MQOO_INPUT_AS_Q_DEF
- 从收到的所有消息头中读取
MQMessage
- 用于
GetPropertyNames("%")
获取所有消息属性的名称 - 用于
GetObjectProperty
获取每个属性的值 - 如果消息格式是
MQSTR
读取正文,ReadString
否则由ReadBytes
发件人
- 创建
MQMessage
- 设置接收到的所有有意义的消息头
MQMessage
——例如MessageId
,ReplyToQueue
名称和其他一些不被复制——而是使用新的或正确的值。 MQMessage
通过使用设置接收到的所有属性SetObjectProperty
- 此步骤包含一些魔法,因为 .NET API 不一致并且从返回的值类型GetObjectProperty
并不总是被接受SetObjectProperty
- 通常我接收String
但我必须通过int
或long
(例如:JmsDeliveryMode、JmsPriority 或 JmsTimestamp)。此步骤还覆盖 JmsDestination 和 JmsReplyTo 的目的地- 通过
WriteString
或编写消息正文WriteBytes
Put
MQQueue
要访问的消息MQOO_OUTPUT
(没有特殊的看跌期权)
我不手动创建 RFH2 结构 - 我让 MQ 基础设施来处理它。所以我的问题是:如何从 .NET 创建有效的 JMS 消息,该消息将被消息驱动 bean 接受?
注意:我不想使用 IBM.XMS - 这个决定是很久以前做出的,因为 IBM 知识库中的一些文章描述了 XMS 和 WMQ 的优缺点。我需要同时支持 JMS 和非 JMS 消息传递。