如何防止 Spring Boot 守护程序/服务器应用程序立即关闭/关闭?

Posted

技术标签:

【中文标题】如何防止 Spring Boot 守护程序/服务器应用程序立即关闭/关闭?【英文标题】:How to prevent Spring Boot daemon/server application from closing/shutting down immediately? 【发布时间】:2019-11-01 17:46:27 【问题描述】:

我的 Spring Boot 应用程序不是 Web 服务器,而是使用自定义协议(在本例中使用 Camel)的服务器。

但是 Spring Boot 在启动后会立即(优雅地)停止。如何防止这种情况发生?

如果 Ctrl+C 或以编程方式,我希望应用程序停止。

@CompileStatic
@Configuration
class CamelConfig 

    @Bean
    CamelContextFactoryBean camelContext() 
        final camelContextFactory = new CamelContextFactoryBean()
        camelContextFactory.id = 'camelContext'
        camelContextFactory
    


【问题讨论】:

你的endpoint怎么暴露的,可以分享一些代码吗? @Haim 它在github.com/lumenitb/lumen/tree/master/social 【参考方案1】:

我找到了解决方案,使用 org.springframework.boot.CommandLineRunner + Thread.currentThread().join(),例如: (注意:下面的代码是 Groovy,不是 Java)

package id.ac.itb.lumen.social

import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
class LumenSocialApplication implements CommandLineRunner 

    private static final log = LoggerFactory.getLogger(LumenSocialApplication.class)

    static void main(String[] args) 
        SpringApplication.run LumenSocialApplication, args
    

    @Override
    void run(String... args) throws Exception 
        log.info('Joining thread, you can press Ctrl+C to shutdown application')
        Thread.currentThread().join()
    

【讨论】:

你的主要方法是什么?这不会编译。 @stealth Rabbi static void main(String[] args) 好的,但是看看 main()。看起来你缺少一些括号。它不编译。 " SpringApplication.run LumenSocialApplication, args" @Stealth Rabbi 我会提到我的代码是 Groovy,而不是 Java 这将破坏使用 SpringBootTest 注释的集成测试。【参考方案2】:

从 Apache Camel 2.17 开始,有一个更清晰的答案。引用http://camel.apache.org/spring-boot.html:

要保持主线程阻塞以使 Camel 保持运行,请包含 spring-boot-starter-web 依赖项,或将 camel.springboot.main-run-controller=true 添加到您的 application.properties 或 application.yml 文件.

您也需要以下依赖项:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-spring-boot-starter</artifactId> <version>2.17.0</version> </dependency>

明确替换&lt;version&gt;2.17.0&lt;/version&gt;或使用camel BOM导入依赖管理信息以保持一致性。

【讨论】:

【参考方案3】:

使用 CountDownLatch 的示例实现:

@Bean
public CountDownLatch closeLatch() 
    return new CountDownLatch(1);


public static void main(String... args) throws InterruptedException 
    ApplicationContext ctx = SpringApplication.run(MyApp.class, args);  

    final CountDownLatch closeLatch = ctx.getBean(CountDownLatch.class);
    Runtime.getRuntime().addShutdownHook(new Thread() 
        @Override
        public void run() 
            closeLatch.countDown();
        
    );
    closeLatch.await();

现在要停止您的应用程序,您可以查找进程 ID 并从控制台发出 kill 命令:

kill <PID>

【讨论】:

【参考方案4】:

Spring Boot 将运行应用程序的任务留给了实现应用程序的协议。例如,请参阅此guide:

还需要一些管理对象,例如CountDownLatch,以保持主线程处于活动状态...

因此,例如,运行 Camel 服务的方式是将 Camel 作为 standalone application 从您的主 Spring Boot 应用程序类运行。

【讨论】:

“本指南”链接已损坏。 看来 Spring 修改了他们的 quides 并且原始文章不再可用。【参考方案5】:

现在变得更简单了。

只需将 camel.springboot.main-run-controller=true 添加到您的 application.properties

【讨论】:

【参考方案6】:

所有线程都完成了,程序会自动关闭。 所以,用@Scheduled注册一个空任务会创建一个循环线程来防止关机。

【讨论】:

这可以是答案而不是评论。请阅读规则。【参考方案7】:

我的项目是 NON WEB Spirng Boot。 我优雅的解决方案是通过 CommandLineRunner 创建一个守护线程。 然后,应用程序不会立即关闭。

 @Bean
    public CommandLineRunner deQueue() 
        return args -> 
            Thread daemonThread;
            consumer.connect(3);
            daemonThread = new Thread(() -> 
                try 
                    consumer.work();
                 catch (InterruptedException e) 
                    logger.info("daemon thread is interrupted", e);
                
            );
            daemonThread.setDaemon(true);
            daemonThread.start();
        ;
    

【讨论】:

【参考方案8】:

要在不部署 Web 应用程序时保持 Java 进程处于活动状态,请将 webEnvironment 属性设置为 false,如下所示:

 SpringApplication sa = new SpringApplication();
 sa.setWebEnvironment(false); //important
 ApplicationContext ctx = sa.run(ApplicationMain.class, args);

【讨论】:

【参考方案9】:

为了让springboot应用程序连续运行,它必须在容器中运行,否则就像任何java应用程序一样,所有线程都完成了,它完成了, 你可以添加

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

它会把它变成 webapp,否则你有责任在你的实现中保持它的活力

【讨论】:

就像我上面说的,它不是一个网络服务器。所以我的问题是......我如何模拟Tomcat的行为?我会停止主线程或类似的东西吗?这样做的“官方”方式是什么?

以上是关于如何防止 Spring Boot 守护程序/服务器应用程序立即关闭/关闭?的主要内容,如果未能解决你的问题,请参考以下文章

基于 Spring Boot (Tomcat) 的应用程序作为守护进程 - 如何停止?

CTRL+C w/ Spring Boot & Gradle 杀死 Gradle 守护进程

如何防止我的 Spring Boot Batch 应用程序在执行测试时运行?

如何防止 Spring Boot / Tomcat (Java8) 进程被 OOM 杀死?

如何理解 Spring Boot 应用程序已准备好工作?

防止来自 Spring Boot 的数据库关闭命令