【问题标题】:JMS message flow between Sender/Receiver发送方/接收方之间的 JMS 消息流
【发布时间】:2012-08-12 11:03:20
【问题描述】:

如果我使用下面的代码来创建发送者和接收者

qsender = qsession.createSender((Queue)msg.getJMSDestination());
qreceiver=qsession.createReceiver((Queue)msg.getJMSDestination());

然后这样做

qsender.send(msg);

它是否只是将消息发送到队列并且它会永远保留在队列中吗?是不是需要调用receiver上的receive()方法或者实现MessageListener接口才能把它传给receiver?

编辑:更多信息

qsender = qsession.createSender((Queue)msg.getJMSDestination());
qreceiver=qsession.createReceiver((Queue)msg.getJMSDestination());

temp1 = qsession.createTemporaryQueue();
responseConsumer = qsession.createConsumer(temp1);
msg.setJMSReplyTo(temp1);

responseConsumer.setMessageListener(responseListener);
msg.setJMSCorrelationID(msg.getJMSCorrelationID()+i);

qsender.send(msg);

在上面的代码中,临时队列是做什么用的?是为了接收消息吗?是接收器吗?如果是,msg.setJMSReplyTo(temp1) 的用途是什么?

【问题讨论】:

    标签: java jms message-queue


    【解决方案1】:

    是的,send(..) 方法会将消息发送到目标队列。并且此消息将保留在队列中,直到您的程序使用接收器接收它或直到您的消息代理正在运行(据我所知)。

    关于你的第二个问题,那么两种方法之间的区别在于下一个:

    receive(..) 方法是同步的(这是这种方法的缺点)。这意味着接收者必须耐心等待消息到达,因为 receive() 消息将阻塞直到消息可用(或直到发生超时条件)。从另一端使用侦听器消费消息是异步过程。您的接收器不会等待。只有当消息被放入查询时,监听器才会调用你的接收方法。

    更新:

    临时目的地用于发送消费者对消息的回复。例如,您的服务器从客户端获取消息并且您需要向他发送响应的情况。在这种情况下,您应该使用临时目的地。服务器应用程序将使用此临时目标(在您的情况下为队列)向客户端发送响应消息。此类队列的范围仅限于创建它的连接,并在连接关闭后立即在服务器端删除。

    您可以在this articleofficila java tutorial 中找到更多详细信息。在第二篇文章中还介绍了如何以及何时使用 JMSCorrelationID。

    这是官方文档中有趣的部分,描述了如何使用临时目的地发送响应消息:

    您可以使用临时目的地来实现简单的请求/回复 机制。如果您创建一个临时目的地并将其指定为 发送消息时 JMSReplyTo 消息头字段的值, 那么消息的消费者可以使用 JMSReplyTo 的值 字段作为它发送回复的目的地。消费者可以 还可以通过设置 JMSCorrelationID 来引用原始请求 JMSMessageID 值的回复消息的头字段 请求的标头字段。例如,一个 onMessage 方法可以 创建一个会话,以便它可以发送对它的消息的回复 收到。它可以使用如下代码:

    producer = session.createProducer(msg.getJMSReplyTo());
    replyMsg = session.createTextMessage("Consumer " +
        "processed message: " + msg.getText());
    replyMsg.setJMSCorrelationID(msg.getJMSMessageID());
    producer.send(replyMsg);
    

    更新 2:

    我想澄清我对队列(或主题)中消息过期时间的回答。默认情况下,消息永远不会过期。但是你可以设置消息的过期时间:

    producer.setTimeToLive(60000);
    

    在此之后,此 MessageProducer 生成的所有消息都将具有指定的过期时间。

    您还可以在具体消息发送期间指定过期时间:

    producer.send(message, DeliveryMode.NON_PERSISTENT, 3, 10000);
    

    其中 10000 表示 10 秒

    【讨论】:

    • 这意味着如果我不调用 receive() 方法或显式实现 MessageListener,它会永远留在队列中吗?我创建了一个临时队列,为其创建了 MessageConsumer,设置了 JMS ReplyTo 并为其设置了 MessageListener。它正在临时队列中获取响应。我的问题 - 如果它不发送给接收方,我们如何获得响应?注意 - 不调用接收/实现 MessageListener。
    • 关于您的第一个问题 - 是的。它将一直保留到您的消息代理运行为止。关于第二个问题 - 请在您的问题中添加一些示例,以便我更好地理解您。
    • 我编辑了我的回复。希望这能帮助你澄清事情。另外我建议您阅读官方 oracle 文档(第二个链接)。这就是我现在正在做的)。
    【解决方案2】:
    1. 是的,它将始终保留在队列中,直到它被消耗或手动或强制从队列中删除。这就是 JMS 的持久性属性,这也是它优于 RPC 的原因。

    2. 关于receive方法,是同步方法,会阻塞线程,直到收到要消费的消息。

    3. 关于消息监听器的实现,它遵循基于拉取的模型。消息代理会在一段时间后继续查询 JMS 服务器,以查看是否有要消费的消息。

    4. 从选项 3 和选项 4 中选择取决于要求,阻塞线程有其自身的缺点,不会让任何事情进一步发展,而轮询也有其自身的缺点,特别是如果 Jms 服务器作为独立运行服务器在远程机器上,并且代理必须在一段时间后使用 RMI 来查询消息。

    更新 :: 如果您查看企业集成请求/回复模式EIP,他们已经解释说,因为消息传递使用异步过程,因此没有来自另一端的确认.如果您想向发件人发送关于该消息的确认,您可以使用msg.setJMSReplyTo,它使用确认消息 Correlation id 与发件人消息 id 匹配以同步请求响应。

    来到临时队列,它提供了在运行时创建队列并绑定到给定连接的好处,而不是在部署时静态定义队列,优点是它提供了轻量级的替代方案并有助于扩展系统在很大程度上。

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 2010-09-14
      • 2015-11-21
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-09
      • 2018-07-18
      相关资源
      最近更新 更多