当前位置: 首页 > 知识库问答 >
问题:

如何防止Spring应用程序上下文关闭,直到启动关闭挂钩

颜修为
2023-03-14

我有一个Spring启动应用程序。

我已经在我的bean中实现了智能生命周期接口,它在它的start方法中启动异步snmp服务器,并在它的Stop方法中停止它。

除了主应用程序上下文在启动后立即停止,所以我的服务器bean也在启动后立即停止之外,所有这些都可以正常工作。

我只需要让spring上下文仅在启动shutdown hook时停止。

这不是一个web应用程序,所以我不需要spring boot starter web,它通过启动webserver来解决这个问题,webserver可以防止上下文停止,直到webserver停止。

我可以使用类似于CountDownLatch的方法,并在上下文开始后立即在我的main方法中等待它为零。像这样的事情:

public static void main(String[] args) throws InterruptedException {
    ConfigurableApplicationContext ctx = SpringApplication.run(SnmpTrapRetranslatorApplication.class, args);
    CountDownLatch snmpServerCloseLatch = ctx.getBean("snmpServerCloseLatch", CountDownLatch.class);
    snmpServerCloseLatch.await();
}

我的服务器bean的start方法将使用count1创建这个锁存器,而stop方法将调用snmpServerCloseLatch。倒计时()

这里描述了这种技术。

但是这样做的错误在于,我的main方法负责等待我的自定义服务器bean停止。我觉得这是不对的。

例如,spring boot starter web是如何做到这一点的?当它启动tomcat时,它会一直运行,直到收到shutdown hook,并且它不需要在main方法中有任何管理代码。只有当上下文接收到shoutdown信号时,它才会停止。

例如,当我在bean中有@Scheduled方法时,也会出现同样的行为。Spring也不会自动停止上下文。仅在CTRL-C上。

我想达到类似的效果。我的main方法应该只有一行:启动上下文。上下文应该启动和停止我的异步服务器时,它启动或停止(已经实现了智能生命周期),并且不应该停止,直到请求关闭(CTRL-C,SIGINT等)。

共有2个答案

司知
2023-03-14
    SpringApplication app = new SpringApplication(Main.class);
    app.setRegisterShutdownHook(false);
    ConfigurableApplicationContext applicationContext= app.run();
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
            //do your things
            applicationContext.close();
        }
    }));
赵英范
2023-03-14

我的调查让我找到了问题的核心:守护进程线程。

我使用的snmp服务器实现(snmp4j)在内部使用守护线程。因此,即使当snmp服务器启动时,JVM中也没有更多的活动用户线程,因此它会退出。

TL/DR:

只需将此方法添加到任何bean中(snmp服务器bean是很好的选择):

@Scheduled(fixedDelay = 1000 * 60 * 60) // every hour
public void doNothing() {
    // Forces Spring Scheduling managing thread to start
}

(不要忘记将@EnableScheduling添加到您的Spring配置中)。

说明:

为了防止在SNMP服务器仍在运行时停止spring上下文,我们需要任何非守护进程线程在JVM中处于活动状态。不一定是主线程。所以我们可以让main方法来完成。

>

  • 我们可以从服务器bean的start方法运行新的非守护进程线程。这个线程将等待某个锁,同时循环检查某个正在运行的变量,而我们的停止方法将把这个正在运行的变量设置为,并在这个锁上设置通知所有

    这样,我们的非守护进程线程将一直处于活动状态,直到触发shotdown钩子(并防止JVM退出)。关闭钩子后,spring context lifecycleclose方法将调用所有SmartLifecyclebean的close方法,这将导致SNMP服务器bean的stop方法调用,这将导致将running设置为false,这将导致我们的非守护进程停止,允许JVM优雅地停止。

    或者我们可以以类似的方式使用Spring的调度线程。它也是非守护线程,所以它将阻止JVM退出。Spring自己管理这个线程,所以当触发关机钩子时,它会自动停止它。

    要使Spring的调度线程启动,我们需要任何bean中的任何@Sched的方法。

    我认为第一种(手动)方法仍然更“正确”,但需要更多的异步编码(众所周知,这很容易出错)。谁知道Spring将来会如何改变它的计划实现呢。

  •  类似资料:
    • 我的Spring Boot应用程序不是Web服务器,但它是使用自定义协议的服务器(在本例中使用Camel)。 但是Spring Boot在启动后立即(优雅地)停止。我如何防止这种情况? 我希望应用程序停止,如果Ctrl C或编程。

    • 我有一个主(屏幕)gui窗口,需要打开几个“多输入”窗口(jdialog或当不可能使用jframe时),例如添加首选项(4个文本字段,带有2个文件选择器和2个单选按钮)。在这些JDialogs(或JFrames)中按OK/Cancel时,我的整个应用程序将关闭。我不想那样。我该怎么防止呢? 第一次尝试:我尝试了intelliJ选项“新- 第二次尝试:我“手工”编写了一个类,创建了一个JDialog

    • 我正在运行一个spring启动应用程序,除了尝试关闭它之外,一切都很好。我在下面的代码中出错 该错误在最后一行生成,spring boot将在2秒等待完成之前关闭level2List,如下所示 是否有任何方法可以命令关闭过程,或确保在关闭之前我没有使用level2List? 沙布尔酒店

    • 启动 1. 轻触主画面上您想启动的应用程序图标。 显示LiveArea™。 2. 轻触[开始]。 中断/继续 按下PS键即可返回LiveArea™。若要继续,请轻触[继续]。 关闭 1. 按下PS键。 返回LiveArea™。 2. 请由画面右上角将LiveArea™撕下。

    • 问题内容: 我的Spring Boot应用程序不是Web服务器,而是使用自定义协议的服务器(在这种情况下使用Camel)。 但是Spring Boot在启动后立即(优美地)停止。我该如何预防? 我希望该应用程序按Ctrl + C或以编程方式停止。 问题答案: 从Apache Camel 2.17开始,有一个更干净的答案。引用http://camel.apache.org/spring- boot.