gpt4 book ai didi

java - 如何防止 Spring 应用程序上下文关闭,直到关闭 Hook 被触发

转载 作者:行者123 更新时间:2023-11-30 06:53:16 25 4
gpt4 key购买 nike

我有一个 spring-boot 应用程序。

我已经实现了 SmartLifecycle我的 bean 中的接口(interface)在它的 start 方法中启动异步 snmp 服务器,并在它的 stop 方法中停止它。

一切正常,除了主应用程序上下文在启动后立即停止,所以我的服务器 bean 也在启动后立即停止。

我只需要让 spring 上下文仅在触发关闭钩子(Hook)时停止。

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

我可以使用 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 方法将创建此闩锁,计数为 1,而 stop 方法将调用 snmpServerCloseLatch.countDown( )

描述了此技术 here .

但这有什么问题是我的 main 方法负责等待我的自定义服务器 bean 停止。我觉得这不对。

例如 spring-boot-starter-web 如何做到这一点?当它启动 tomcat 时,它会一直运行直到收到关闭钩子(Hook),并且它不需要在 main 方法中有任何管理代码。它仅在上下文接收到 shoutdown 信号时停止。

相同的行为是例如当我的 bean 中有 @Scheduled 方法时。 Spring 也不会自动停止上下文。仅适用于 CTRL-C

我想达到类似的效果。我的 main 方法应该只有一行:启动上下文。上下文应该在我的异步服务器启动或停止时启动和停止(已通过 SmartLifecycle 实现)并且在请求关闭(CTRL-C、SIGINT 等)之前不应停止。

最佳答案

我的调查让我找到了问题的核心:daemon threads .

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

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 中处于 Activity 状态。不一定是 main 线程。所以我们可以让 main 方法结束。

  1. 我们可以从服务器 bean 的 start 方法运行新的非守护线程。此线程将等待 while 中的一些锁,循环检查一些running 变量,而我们的stop 方法将设置此锁上的 running 变量为 falsenotifyAll

    这样,我们的非守护线程将一直存在,直到触发 shotdown 钩子(Hook)(并防止 JVM 退出)。在 shutdown hook 之后,spring context lifecycle close 方法将调用所有 SmartLifecycle bean 的 close 方法,这将导致 SNMP server bean 的 stop 方法调用,这将导致将 running 设置为 false,这将导致我们的非守护线程停止,从而允许 JVM 正常停止。

  2. 或者我们可以用类似的方式使用 Spring 的调度线程。它也是非守护线程,所以它会阻止 JVM 退出。而 Spring 自己管理这个线程,所以它会在触发 shutdown hook 时自动停止它。

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


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

关于java - 如何防止 Spring 应用程序上下文关闭,直到关闭 Hook 被触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37754410/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com