暂时禁用消息侦听器的好方法是什么? 我要解决的问题是:
现在,我正在使用 Sun App Server。 我通过在 MessageConsumer 中将消息侦听器设置为 null 来禁用消息侦听器,然后使用 setMessageListener(myOldMessageListener) 再次启用它,但此后我不再收到任何消息。
如果在系统准备好再次处理消息之前不从
onMessage()
侦听器方法返回,会怎么样?这将阻止 JMS 向该消费者传递另一条消息。
这相当于在同步情况下不调用
receive()
的异步。
给定的 JMS 会话没有多线程,因此消息管道将被阻塞,直到
onMessage()
方法返回。
我不熟悉动态调用
setMessageListener()
的含义。 javadoc 说,如果调用“当现有侦听器或同步消费者正在使用消息时”,则存在未定义的行为。 如果您从 onMessage()
内部拨打电话,听起来就像遇到了未定义的情况。连接级别有 start
/stop 方法(如果这对您来说不是太粗粒度的话)。
MBeanServer mbeanServer = MBeanServerLocator.locateJBoss();
ObjectName objName = new ObjectName("jboss.j2ee:ear=MessageGateway.ear,jar=MessageGateway-EJB.jar,name=MessageSenderMDB,service=EJB3");
JMSContainerInvokerMBean invoker = (JMSContainerInvokerMBean) MBeanProxy.get(JMSContainerInvokerMBean.class, objName, mbeanServer);
invoker.stop(); //Stop MDB
invoker.start(); //Start MDB
messageConsumer.setMessageListener(null);
在 MessageListener 实现中并安排重建任务(例如在 ScheduledExecutorService 中)。这个任务应该调用
connection.stop();
messageConsumer.setMessageListener(YOUR_NEW_LISTENER);
connection.start();
它会起作用的。 start() 和 stop() 方法用于重新启动传递结构(不是 TCP 连接)。
阅读 Javadoc
https://docs.oracle.com/javaee/7/api/javax/jms/Connection.html#stop--暂时停止连接传递传入消息。可以使用连接的启动方法重新启动传送。当连接停止时,将禁止向所有连接的消息使用者传递:同步接收块,并且消息不会传递给消息侦听器。通过 JNDI 找到 MBean 并停止它(在 JBoss EAP 中,您可以获取该 bean 并调用其上的方法
stopDelivery()
AtomicBoolean()
ACCEPTING_MESSAGES
,将其设置为false,并在onMessage()
中添加检查其值的逻辑,如果为false,则不接受新消息,直接返回。
private void stopJmsDelivery(String name) {
try {
MBeanServer s = ManagementFactory.getPlatformMBeanServer();
ObjectName n = ObjectName.getInstance(name);
s.invoke(n, "stopDelivery", null, null);
} catch (Exception e) {
log.error("Failed to stop JMS: ", e);
} catch (Throwable throwable) {
log.error("Failed to stop JMS(generic): ", throwable);
}
}
JBoss EAP 中的 arg 是这样的:
"jboss.as:deployment=my-service.ear,subdeployment=some.jar,subsystem=ejb3,message-driven-bean=MyMDB"
使用 JBoss EAP 管理控制台检查确切的字符串。