有时从ibm mq返回的响应与请求不匹配

时间:2019-05-28 15:10:30

标签: java multithreading ibm-mq mule4

我复制了有关如何调用IBM MQ的Java客户端代码,并将请求传递到队列,但是有时我从队列中返回了错误的响应。

例如,如果我提交以下请求: F LOYFI6331760101046481882

我希望从回复中我会得到 F LOYFA36331760101046481882

但实际上我得到了 F LOYFA36331760101051292448

您会看到卡号错误。

这是代码

import javax.jms.BytesMessage;
import javax.jms.Destination;
import javax.jms.JMSConsumer;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.JMSProducer;
import javax.jms.TextMessage;

import com.ibm.msg.client.jms.JmsConnectionFactory;
import com.ibm.msg.client.jms.JmsFactoryFactory;
import com.ibm.msg.client.wmq.WMQConstants;

public class MQClient {
    // System exit status value (assume unset value to be 1)
    private static int status = 1;

    public static byte[] sendAndReceive(String HOST, Integer PORT, String QMGR, String CHANNEL, String requestQueue, String responseQueue, String payload) {
        // Variables
        JMSContext context = null;
        Destination destination = null;
        JMSProducer producer = null;
        JMSConsumer consumer = null;
        BytesMessage receivedMessage = null;
        byte[] result = null;
        try {
            // Create a connection factory
            JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
            JmsConnectionFactory cf = ff.createConnectionFactory();

            // Set the properties
            cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
            cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
            cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
            cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
            cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QMGR);
            cf.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "JmsPutGet (JMS)");
            cf.setStringProperty(WMQConstants.WMQ_TARGET_CLIENT, "1");
            // Create JMS objects
            context = cf.createContext();
            destination = context.createQueue("queue:///" + requestQueue +"?targetClient=1");

            TextMessage message = context.createTextMessage(payload);

            producer = context.createProducer();
            producer.send(destination, message);
            System.out.println("Sent message:\n" + message);

            destination = context.createQueue("queue:///" + responseQueue + "?targetClient=1");
            consumer = context.createConsumer(destination); // autoclosable
            receivedMessage= (BytesMessage)consumer.receive();
            System.out.println("Receiving message:" + receivedMessage);
            int text_length = new Long(receivedMessage.getBodyLength()).intValue();
            result = new byte[text_length];
            receivedMessage.readBytes(result, text_length);

            System.out.println("\nReceived message:\n" + new String(result));

            recordSuccess();

        } catch (JMSException jmsex) {
            recordFailure(jmsex);
        }finally {
            context.close();
        }

        return result;

    }
}

我还有另一个要同时运行的项目,以调用MQClient.sendAndReceive()hostportQMGRchannelrequestQueueresponseQueue,只有payload不同。

那我该如何修复上面的代码,以确保始终得到与请求相对应的正确响应?

编辑: 1.对于JoshMac问题,app是IBM MQ的意思吗?还是会调用我的sendAndReceive函数的应用?

  1. 这是我拥有的流程,我使用m子流程从POS接收请求,处理该请求,这需要调用IBM MQ(位于AS400上),以从MQ取回响应,然后发送回POS。 (在此示例中,我需要向INQ1提交请求,并从INQR1获取响应)。根据以下答案,似乎sendAndReceive函数被视为Requester,我需要另一个流程来调用Responder来处理响应,因此receivedMessage= (BytesMessage)consumer.receive();不会卡住了吗?如果我错了请纠正我

2 个答案:

答案 0 :(得分:0)

  

您可以使用其他主题进行区分吗?

在进行点对点消息传递时,这是一个坏主意。

destination = context.createQueue("queue:///" + responseQueue + "?targetClient=1");

听起来您的responseQueue在多个使用者之间共享。您有2个选择:

  1. 创建您自己的临时动态队列并将其设置为“答复” 排队

Queue replyQ = session.createTemporaryQueue();
  1. 使用MsgId / CorrelId请求-答复消息传递模式。

即请遵循此页面上的建议:Not able to get response from IBM MQ using JMS application

答案 1 :(得分:0)

似乎所有响应都已发送到INQR1。为了帮助您的应用识别出哪些响应以及哪些响应可以忽略,可以使用选择器,并且通常可以使用相关性ID作为选择器,尽管您可以使用其他字段。

本质上,您使用的是具有JMS示例的请求/响应模式-https://github.com/ibm-messaging/mq-dev-patterns/tree/master/JMS

您的请求者将具有以下逻辑:

String correlationID = String.format("%24.24s", UUID.randomUUID().toString());
message.setJMSCorrelationIDAsBytes(b);

生成相关性ID,并将其添加到消息中。

您的请求者然后将创建一个基于相关ID的选择器来过滤响应队列:

try {
      b = correlationID.getBytes();
      selector = "JMSCorrelationID='ID:" + getHexString(b) + "'";
    } catch (Exception e) {
       ...
    }

您用来构造消息使用者的

JMSConsumer consumer = context.createConsumer(requestQueue, selector);
Message receivedMessage = consumer.receive();

当您的响应者收到初始请求时,它可以保留相关ID:

String correlationID = receivedMessage.getJMSCorrelationID();

并使用它来设置响应的相关ID:

message.setJMSCorrelationID(correlationID);