【问题标题】:How to make MessageListener stop listening for messages in JMS when it receives a certain message?如何让 MessageListener 在收到某个消息时停止侦听 JMS 中的消息?
【发布时间】:2013-09-18 05:41:37
【问题描述】:

我有一个消息监听器正在接收一些文本消息。当它收到一个 ObjectMessage 时,我希望它停止监听队列。我的问题是,当我在 onMessage(Message msg) 方法中调用 consumer.close() 时,ObjectMessage 似乎没有从队列中删除。如果我在 onMessage() 方法之后使用一些标记来告诉 consuemr 关闭,则侦听器可能会在它实际关闭之前使用另一条消息。有什么建议?这是一些代码。 Session、Connection 和 InitialContext 尚未关闭。

public class MyListener implements MessageListener{
    MessageConsumer consumer;

    public MyListener(MessageConsumer mc){
        consumer = mc;
    }

    @Override
    public void onMessage(Message msg) {
        try{
            if(msg instanceof ObjectMessage){
                consumer.close();
            }
            if (msg instanceof TextMessage){
                TextMessage tmsg = (TextMessage) msg;
                String xml = tmsg.getText();
                // do some stuff                
            }

       }catch(Exception e){
           e.printStackTrace();
       }
    }

【问题讨论】:

  • 真的是Queue 还是Topic?我相信消息一旦被检索到,就会从Queue 中消失。
  • 这是一个队列。我也有同样的想法,但是下次我尝试接收 TextMessages 时,它会在第一次调用 onMessage 时关闭...大概是因为对象消息仍然存在

标签: java jms message-listener


【解决方案1】:

不要使用异步MessageListener

改为在循环中的主线程中使用正常的同步receive 方法。如果您收到您的特殊消息,您可以确认并从循环中中断以关闭会话并终止程序。

【讨论】:

    【解决方案2】:

    根据JMS规范,你不能从onMessage()调用connection.stop()connection.close()是正确的,但是你可以从其他线程调用connection.close()connection.stop(),所以在我的情况下,我只是在需要停止连接时从 onMessage() 设置 volatile 变量,并在其他线程中检查这个变量,我可以在其中调用 connection.stop()connection.close() 而不会出现异常或死锁。

    >来自 JMS 2.0 规范:

    6.1.5。暂停传入消息的传递 如果调用 stop 时任何消息侦听器正在运行,则 stop 必须等到所有消息侦听器都在运行 在它可能返回之前已经返回。虽然这些消息监听器是 完成后,他们必须拥有连接的全部服务 可供他们使用。消息侦听器不得尝试停止自己的 连接,因为这会导致死锁。 JMS 提供者必须 检测到这一点并抛出 javax.jms.IllegalStateException。

    >来自 JMS 1.1:

    4.3.4 暂停传入消息的传递 如果调用 stop 时 MessageListeners 正在运行,stop 必须等到它们都 在它可能返回之前返回。虽然这些 MessageListener 是 完成后,他们必须拥有连接的全部服务 可供他们使用。

    【讨论】:

      【解决方案3】:

      首先阅读documentation。您可能有另一个线程访问MessageConsumer,而调用close() 的线程将阻塞,直到其他线程完成。

      【讨论】:

        【解决方案4】:

        在尝试解决这个问题几个小时后,我想我找到了一种方法来停止异步消息使用者 (MessageListener)。 该解决方案涉及使用 Java 锁(同步语句和等待/通知方法)。

        首先,在您的主线程上,您需要在启动 JMS 连接后锁定消息侦听器并调用消息侦听器“等待”方法。 在您的消息侦听器上,您需要再次锁定消息侦听器,然后调用“全部通知”方法。

          // Main thread ...
          public static void main(String[] args) {
            // ...
            try {
              Connection jmsConn;
              MessageConsumer msgConsumer;
              MessageListener msgListener;
              // ...
              msgConsumer.setMessageListener(msgListener);
              // ...
              synchronized (msgListener) {
                jmsConn.start();
                msgListener.wait();
              }
              jmsConn.stop();
              //...
            } catch (Exception e) {
              // ...
            }
          }
        
        
          // MessageListener onMessage...
          public void onMessage(Message jmsMsg) {
            try {
              // ...
              synchronized (this) {
                this.notifyAll();
              }
            } catch (Exception e) {
              // ...
            }
          }
        

        米格尔·亚伯拉罕

        【讨论】:

          【解决方案5】:

          这可能有点老了,但由于我遇到了同样的问题并遇到了它,所以我想我会发布我的发现来帮助其他人。

          我遇到了与问题相同的问题,我创建了一个设置异步侦听器的 JMS 接收器类;

          TopicSubscriber receiver = myTopicSession.createSubscriber(myTopic);  
          JmsMessageListener listener = new JmsMessageListener();
          receiver.setMessageListener(listener);
          

          然后我无法以一种很好的方式终止监听器。

          我发现解决方案实际上是关闭与我的主题的连接。而且这也会终止侦听器线程。

          myTopicConnection.close();
          

          这意味着在我的主线程中,我必须保留一个指向我创建的 JMS 接收器类的链接,然后调用 close() 方法将其关闭。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-18
            相关资源
            最近更新 更多