我正在开发一个Spring引导JMS应用程序,该应用程序严格使用bean注释进行设置,并且正在从WebshpereMQ中读取消息。一切正常,除了我无法弄清楚如何安全地关闭这个应用程序。一旦我的JMSListener方法读取所有消息,它就会保持空闲状态。我建立了与队列的初始连接并访问队列深度,因此理想情况下,当队列深度为零时,需要将其包装起来并关闭。我当前的解决方法(我根本不喜欢它)是我在深度为零时调用的一个小方法(来自侦听器内部, yikes ):
public void shutDownApplication() {
logger.info("Initiating shutdown of application...");
System.out.println("Terminating application...");
Thread.currentThread().interrupt();
System.exit(0);
}
我不喜欢这个解决方案。 Spring也没有,因为这显然是作为一个错误在进程中断而且在应用程序死亡之前我的JMSListener启动了一个回滚并将剩下的最后一条消息放回队列。
在查看以下资料后我尝试了其他一些解决方案:
How can I Stop/start/Pause a @JmsListener (the clean way)
How to gracefully shut down a Spring JMS MessageListenerAdapter
这是我最近的解决方案:
public class JMSShutdownService {
public void initiateShutdown() {
JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry();
Collection<MessageListenerContainer> col = jmsListenerEndpointRegistry
.getListenerContainers();
for (MessageListenerContainer cont : col) {
cont.stop(Thread.currentThread());
}
System.exit(0);
}
}
这会终止应用程序,但仍会将最后一条消息放回队列中。有很多错综复杂的Spring我还在努力去理解,所以这一切都归结为此。我觉得主要的问题是它在侦听器内部我发出关闭信号。从我收集的内容来看,听众不应对此负责。但我不确定如何在侦听器启动之前定义关闭应用程序的方法,或者在队列深度为零时如何弹出侦听器。
有什么想法吗?
答案 0 :(得分:2)
JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry();
这没用;新的注册表将没有任何容器,如果您使用@JmsListener
,则需要从应用程序上下文中获取注册表。
System.exit(0);
这只会杀死JVM。
底线是你应该停在不同线程上的容器上 - 使用任务执行器来启动一个新线程来停止容器;容器将在停止之前等待线程退出侦听器。
停止容器后,您需要等待一段宽限期才能终止JVM。
你怎么知道你已经完成了?停止容器后,可能会显示另一条消息,在这种情况下,由于容器正在停止,您可能会在日志中看到有关消息被拒绝的噪音。
修改强>
在我的听众中......
...
if (timeToShutDown()) {
Executors.newSingleThreadExecutor.execute(new Runnable() {
public void run() {
stopTheContainer();
}
}
}
// exit the listener so the container can actually stop.