我有一个消息监听器正在接收一些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();
}
}
答案 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()方法将其关闭。