我有一个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等)。
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();
}
}));
我的调查让我找到了问题的核心:守护进程线程。
我使用的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 lifecycle
close
方法将调用所有SmartLifecycle
bean的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.