如何使MessageListener在收到某条消息时停止侦听JMS中的消息?

时间:2013-09-13 13:44:26

标签: java jms message-listener

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

5 个答案:

答案 0 :(得分:4)

不要使用异步MessageListener

而是在循环中使用主线程中的常规同步receive方法。如果您收到特殊消息,您可以确认并退出循环以关闭会话,并终止该程序。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

  // 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

答案 3 :(得分:0)

根据 JMS规范,您无法从connection.stop()致电connection.close()onMessage(),但您可以致电connection.close()connection.stop()来自其他线程,所以在我的情况下,我只是在需要停止连接时从onMessage()设置volatile变量,并在其他线程中检查此变量,我可以在其中调用connection.stop()和{ {1}}没有得到异常或死锁。

<强>&GT;来自JMS 2.0规范:

  

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

     

<强>&GT;来自JMS 1.1:

     

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

答案 4 :(得分:-1)

这可能有点旧,但由于我遇到同样的问题而遇到过它,我想我会发布我的发现以帮助其他人。

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

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

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

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

myTopicConnection.close();

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