安全终止 Spring JMS 应用程序
Safely Terminating a Spring JMS application
我正在开发 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 有很多错综复杂的地方我还在努力理解,所以这一切都归结为这一点。我觉得主要问题是它在我发出关闭信号的侦听器内部。据我所知,听众不应该对此负责。但是我不确定如何定义一种在侦听器启动之前关闭应用程序的方法,或者如何在队列深度为零时弹出侦听器。
有什么想法吗?
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.
我正在开发 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 有很多错综复杂的地方我还在努力理解,所以这一切都归结为这一点。我觉得主要问题是它在我发出关闭信号的侦听器内部。据我所知,听众不应该对此负责。但是我不确定如何定义一种在侦听器启动之前关闭应用程序的方法,或者如何在队列深度为零时弹出侦听器。
有什么想法吗?
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.