Java 当MessageListener接收到特定消息时,如何使其停止侦听JMS中的消息?

Java 当MessageListener接收到特定消息时,如何使其停止侦听JMS中的消息?,java,jms,message-listener,Java,Jms,Message Listener,我有一个消息侦听器正在接收一些文本消息。当它收到ObjectMessage时,我希望它停止侦听队列。我的问题是,当我在onMessage(Message msg)方法中调用consumer.close()时,ObjectMessage似乎没有从队列中删除。如果我在onMessage()方法之后使用一些标记告诉consuemr关闭,那么监听器可能会在实际关闭之前使用另一条消息。有什么建议吗?下面是一些代码。会话、连接和InitialContext尚未关闭 public class MyListen

我有一个消息侦听器正在接收一些文本消息。当它收到ObjectMessage时,我希望它停止侦听队列。我的问题是,当我在onMessage(Message msg)方法中调用consumer.close()时,ObjectMessage似乎没有从队列中删除。如果我在onMessage()方法之后使用一些标记告诉consuemr关闭,那么监听器可能会在实际关闭之前使用另一条消息。有什么建议吗?下面是一些代码。会话、连接和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();
       }
    }

读第一段。您可能有另一个线程访问
MessageConsumer
,而调用
close()
的线程将阻塞,直到其他线程完成为止。

请勿使用异步
MessageListener


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

在尝试解决此问题几个小时后,我想我找到了停止异步消息使用者(MessageListener)的方法。 解决方案涉及使用Java锁(同步语句和wait/notify方法)

首先,在主线程上,您需要在启动JMS连接后锁定消息侦听器,并调用消息侦听器“wait”方法。 在消息侦听器上,需要再次锁定消息侦听器,然后调用“notifyall”方法

  // 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) {
      // ...
    }
  }

米格尔·亚伯拉罕(Miguel Abraham)

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

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

TopicSubscriber receiver = myTopicSession.createSubscriber(myTopic);  
JmsMessageListener listener = new JmsMessageListener();
receiver.setMessageListener(listener);
然后我就不能用一种好的方式终止听众

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

myTopicConnection.close();

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

根据JMS规范,您不能调用
connection.stop()
connection.close()
from
onMessage()
,这是正确的,但是您可以从其他线程调用
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必须等待,直到所有消息都已发送 在它可能返回之前返回。而这些消息侦听器是 完成后,他们必须拥有连接的全部服务 可供他们使用


它真的是一个
队列
还是一个
主题
?我相信消息一旦被检索,就会从
队列中消失。这是一个队列。我也这么想,但下次我尝试接收短信时,它会在第一次调用onMessage时关闭。。。大概是因为对象消息仍然存在