Java 安全终止SpringJMS应用程序

Java 安全终止SpringJMS应用程序,java,spring-boot,spring-jms,Java,Spring Boot,Spring Jms,我正在开发一个SpringBootJMS应用程序,该应用程序严格使用bean注释进行设置,并从WebshpereMQ读取消息。一切正常,但我不知道如何安全关闭此应用程序。一旦我的JMSListener方法读取了所有消息,它就一直处于空闲状态。我与队列建立初始连接并访问队列深度,因此理想情况下,当队列深度为零时,它需要将其打包并关闭。我目前的解决方法(我一点也不喜欢)是在深度为零时调用的一个小方法(从监听器内部,yikes): public void shutDownApplication() {

我正在开发一个SpringBootJMS应用程序,该应用程序严格使用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启动回滚并将最后一条消息放回队列

在查看了以下来源后,我尝试了其他一些解决方案:

这是我最近的解决方案:

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);
    }

}
公共类JMSShutdownService{
公共无效启动器停止(){
JmsListenerEndpointRegistry JmsListenerEndpointRegistry=新JmsListenerEndpointRegistry();
集合col=jmsListenerEndpointRegistry
.getListenerContainers();
对于(MessageListenerContainer cont:col){
cont.stop(Thread.currentThread());
}
系统出口(0);
}
}
这会终止应用程序,但仍会将最后一条消息放回队列。我仍在努力理解春天的许多复杂之处,所以一切都归结于此。我觉得主要的问题是,它在我发出关机信号的侦听器内部。据我所知,听众不应该对此负责。但我不确定如何定义在侦听器启动之前关闭应用程序的方法,或者在队列深度为零时如何从侦听器中弹出

有什么想法吗

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.

`使用任务执行器启动一个新线程以停止容器“”:这个新线程创建的确切时间是什么时候?在听众开始之前,还是在听众中?然后这个线程告诉容器“嘿,我收到了我们完成的信号,关闭它”?对-侦听器可以确定是时候停止并调用
Executors.newSingleThreadExecutor.execute(…)
了,然后在
Runnable
停止容器,这将释放侦听器线程以退出,容器将在实际停止之前等待。最后一个问题,我对此表示歉意,因为我想我知道答案,但我想确认一下。当你说“然后在Runnable中”时,Runnable指的是新创建的线程,是吗?请看我的编辑-执行器在新线程上调用一个
Runnable
。只是想回来说这像做梦一样工作。我还必须将bean从
DefaultJmsListenerContainerFactory
更改为
DefaultMessageListenerContainer
。我不知道这是否是完全必要的,但我似乎不知道如何获得容器,否则。我还必须将
autoStartup
设置为false,以避免日志中出现错误。一切都正常,但如果你愿意提供这些变化的意见,我们也会很感激,但你已经为我做了很多。