如何关闭 Spring Boot 命令行应用程序

问题描述 投票:0回答:9

我正在使用 Spring Boot 构建命令行 java 应用程序以使其快速运行。

应用程序加载不同类型的文件(例如 CSV)并将它们加载到 Cassandra 数据库中。它不使用任何网络组件,它不是一个网络应用程序。

我遇到的问题是工作完成后停止应用程序。我使用带有

@Component
的 Spring CommandLineRunner 接口来运行任务,如下所示,但是当工作完成时,应用程序不会停止,它由于某种原因继续运行,我找不到停止它的方法.

@Component
public class OneTimeRunner implements CommandLineRunner {

    @Autowired
    private CassandraOperations cassandra;

    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void run(String... args) throws Exception {
        // do some work here and then quit
        context.close();
    }
}

更新:问题似乎是

spring-cassandra
,因为项目中没有其他内容。有谁知道为什么它让线程在后台运行以防止应用程序停止?

更新:通过更新到最新的 Spring Boot 版本,问题消失了。

java spring spring-boot spring-data-cassandra
9个回答
59
投票

我找到了解决办法。你可以用这个:

public static void main(String[] args) {
    SpringApplication.run(RsscollectorApplication.class, args).close();
    System.out.println("done");
}

运行时只需使用

.close()


31
投票

答案取决于仍在工作的是什么。您可能可以通过线程转储找到答案(例如使用 jstack)。但如果它是由 Spring 启动的任何内容,您应该能够使用

ConfigurableApplicationContext.close()
在 main() 方法(或在
CommandLineRunner
中)停止该应用程序。


28
投票

这是 @EliuX 答案与 @Quan Vo 的组合。谢谢两位!

主要的区别是我将 SpringApplication.exit(context) 响应代码作为参数传递给 System.exit(),因此如果关闭 Spring 上下文时出现错误,您会注意到。

SpringApplication.exit() 将关闭 Spring 上下文。

System.exit() 将关闭应用程序。

@Component
public class OneTimeRunner implements CommandLineRunner {

    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void run(String... args) throws Exception { 
       System.exit(SpringApplication.exit(context));
    }
}

5
投票

我在当前的项目(spring boot应用程序)中也遇到了这个问题。 我的解决方案是:

// releasing all resources
((ConfigurableApplicationContext) ctx).close();
// Close application
System.exit(0);

context.close()
不要停止我们的控制台应用程序,它只是释放资源。


5
投票

使用

org.springframework.boot.SpringApplication#exit
。例如

@Component
public class OneTimeRunner implements CommandLineRunner {

    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void run(String... args) throws Exception { 
        SpringApplication.exit(context);
    }
}

2
投票

我开发了一个命令行 Spring 应用程序(Spring 版本 2.7),该应用程序在执行业务逻辑后停止。我所需要的只是遵循应用程序配置,告诉 spring 这不是一个 Web 应用程序。

配置

spring:
  main:
    web-application-type: none

Spring主类

@SpringBootApplication
public class DataInjectionApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(DataInjectionApplication.class, args);
    }


    @Override
    public void run(String... args) {
        
        //execute business logic here

    }
}

1
投票

命令行应用程序在关闭时应返回退出代码。这篇文章描述了 ExitCodeGenerator 的使用以及如何在 spring 应用程序中使用它。 这种方法对我有用:

@SpringBootApplication 公共类 ExitCodeGeneratorDemoApplication 实现 ExitCodeGenerator {

public static void main(String[] args) {
    System.exit(SpringApplication
      .exit(SpringApplication.run(DemoApplication.class, args)));
}

@Override
public int getExitCode() {
    return 42;
}

}

https://www.baeldung.com/spring-boot-exit-codes


0
投票

当没有挂起的线程时,应用程序会自动停止,而不会出现

exit()
。我遇到了同样的问题,最后我找到了发生这种情况的原因。我总是依赖 spring 机制,它会在应用程序退出时关闭所有
Closeable
beans,但它是在 JVM 关闭挂钩上调用的,因此在某些非守护线程运行之前永远不会调用它。我通过在
CommandLineRunner
中手动关闭所有具有打开线程的bean解决了这个问题。不幸的是,它对于自动配置创建的所有 bean 也是必需的(例如
spring-data-elasticsearch
创建此类 bean)。


0
投票

使用命令行运行程序时存在一个常见的陷阱。启动时:

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

(通常是简单的复制粘贴错误)Spring Boot 将启动 servlet 容器,这将防止应用程序在命令行运行程序完成后停止。这就是为什么在某些情况下

.close()
System.exit()
会有所帮助,因为它会关闭容器,然后关闭应用程序。

如果您不需要容器,只需使用:

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

并且应用程序将在命令行完成后关闭,而无需关闭/退出调用(假设没有挂起的线程,如Dave Syer在他的answer中解释的那样)。

© www.soinside.com 2019 - 2024. All rights reserved.