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