问题 如何进行JMS同步请求


我有一个webapp,可以从外部应用程序获取和显示数据,只能通过消息传递(JMS)访问。

因此,如果用户在浏览器上提交请求,则相同的HTTP请求线程必须与Messaging系统(MQ Series)交互,以便相同的请求线程可以显示从Messaging System接收的数据。

我可以在这里使用一种模式吗?我在网上看到了一些模糊的引用,它们以这种方式使用“Correlation ID”:

Msg m = new TextMsg("findDataXYZ");
String cr_id = m.setCorrelationID(id);

sendQueue.send(m).

// now start listening to the Queue for a msg that bears that specific cr_id

Response r = receiverQueue.receive(cr_id);

那里有更好的东西吗?我发现的其他模式希望响应是异步接收的......这对我来说不是一个选项,因为我必须在同一个HTTP请求上发回响应。


11463
2018-05-28 01:25


起源



答案:


首先,打开响应队列。然后将该对象传递给消息上的set reply-to方法。这样,响应您的请求的服务就知道在哪里发送回复。通常,服务会将消息ID复制到相关ID字段,因此在您发送消息时,请获取您返回并使用的消息ID  听取回复队列。当然,如果您使用动态回复队列,即使这不是必要的 - 只需侦听队列中的下一条消息。

有示例代码显示所有这些。如果您安装到默认位置,示例代码将保留在 "C:\Program Files (x86)\IBM\WebSphere MQ\tools\jms\samples\simple\SimpleRequestor.java" 在Windows框或 /var/mqm/toolsjms/samples/simple/SimpleRequestor.java 在* nix框上。

你有机会想知道“安装什么,确切地说?” WMQ客户端安装可免费下载 SupportPac MQC71


5
2018-05-28 03:41



感谢你的回答。所以看起来模式是:1。使用常规的“发送”队列发送请求。但是对于接收,请使用“临时队列”。我安装了您提到的客户端工具,SimpleRequestor类执行此操作: tempDestination = session.createTemporaryQueue(); consumer = session.createConsumer(tempDestination);  它看起来很棒,但它是否可以在生产中使用的代码,我们在expecteg每秒处理1000个这样的请求?看起来我们将为每个请求创建一个临时队列。 - rk2010
WMQ重用临时队列,一切都在内存中,因此获取句柄非常快。您需要密切注意DLQ,因为如果您的应用程序在回复显示之前超时,则回复将路由到DLQ。如果您希望为响应队列使用预定义的队列,那么也可以。如果多个实例使用相同的队列,则需要通过关联ID执行GET。但是,如果消息是持久的,则必须使用预定义或永久动态队列。 - T.Rob


答案:


首先,打开响应队列。然后将该对象传递给消息上的set reply-to方法。这样,响应您的请求的服务就知道在哪里发送回复。通常,服务会将消息ID复制到相关ID字段,因此在您发送消息时,请获取您返回并使用的消息ID  听取回复队列。当然,如果您使用动态回复队列,即使这不是必要的 - 只需侦听队列中的下一条消息。

有示例代码显示所有这些。如果您安装到默认位置,示例代码将保留在 "C:\Program Files (x86)\IBM\WebSphere MQ\tools\jms\samples\simple\SimpleRequestor.java" 在Windows框或 /var/mqm/toolsjms/samples/simple/SimpleRequestor.java 在* nix框上。

你有机会想知道“安装什么,确切地说?” WMQ客户端安装可免费下载 SupportPac MQC71


5
2018-05-28 03:41



感谢你的回答。所以看起来模式是:1。使用常规的“发送”队列发送请求。但是对于接收,请使用“临时队列”。我安装了您提到的客户端工具,SimpleRequestor类执行此操作: tempDestination = session.createTemporaryQueue(); consumer = session.createConsumer(tempDestination);  它看起来很棒,但它是否可以在生产中使用的代码,我们在expecteg每秒处理1000个这样的请求?看起来我们将为每个请求创建一个临时队列。 - rk2010
WMQ重用临时队列,一切都在内存中,因此获取句柄非常快。您需要密切注意DLQ,因为如果您的应用程序在回复显示之前超时,则回复将路由到DLQ。如果您希望为响应队列使用预定义的队列,那么也可以。如果多个实例使用相同的队列,则需要通过关联ID执行GET。但是,如果消息是持久的,则必须使用预定义或永久动态队列。 - T.Rob


请求/回复消息传递模式对您的要求很有用。您通常使用CorrelationId来关联请求和回复消息。

在发送请求消息时,您可以在消息上设置JMSReplyTo目标。通常,临时队列用作JMSReplyTo目标。在创建消费者以接收响应时,使用带有JMSCorrelationId的选择器,类似于

cons = session.createConsumer(tempDestination,"JMSCorrelationId="+requestMsg.JMSMessageId);

另一方面,处理请求消息的应用程序必须使用JMSReplyTo目标来发送响应。它还必须使用请求消息的MessageId并将其设置为响应消息的CorrelationId。


10
2018-05-28 04:13



如果我一个接一个地发送请求,那么我应该创建 新 每个请求的临时队列?或者为所有请求重用相同的临时队列?是否允许这种重用?如果是这样,什么方法是好的,重用或创建? - Nawaz
另外,在你的建议中,如果我设置了 "JMSCorrelationId="+requestMsg.JMSMessageId,那么我想我不能 重用 同一个消费者获得的不仅仅是回复,因为回复的相关ID会有所不同?此外,如果我为每个请求使用新的tempQueue,那么我不需要设置消息选择器,因为tempQueue仅专用于一个响应。无论哪种方式,我都没有看到任何理由设置 JMSCorrelationId="+requestMsg.JMSMessageId,因为无论如何,只有一个响应会传达给消费者。我对吗? - Nawaz
是的,如果您为每个请求使用tempQueue,那么您不需要使用选择器。仅在共享队列时才需要选择器。 - Shashi
谢谢。这对我来说很有意义。现在接下来的问题是,如果我在选择器中使用消息ID,那么我就无法重用消费者。对? - Nawaz
是。那是对的。 - Shashi