我正在使用 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 版本,问题消失了。
我找到了解决办法。你可以用这个:
public static void main(String[] args) {
SpringApplication.run(RsscollectorApplication.class, args).close();
System.out.println("done");
}
运行时只需使用
.close()
。
答案取决于仍在工作的是什么。您可能可以通过线程转储找到答案(例如使用 jstack)。但如果它是由 Spring 启动的任何内容,您应该能够使用
ConfigurableApplicationContext.close()
在 main() 方法(或在 CommandLineRunner
中)停止该应用程序。
这是 @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));
}
}
我在当前的项目(spring boot应用程序)中也遇到了这个问题。 我的解决方案是:
// releasing all resources
((ConfigurableApplicationContext) ctx).close();
// Close application
System.exit(0);
context.close()
不要停止我们的控制台应用程序,它只是释放资源。
使用
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);
}
}
我开发了一个命令行 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
}
}
命令行应用程序在关闭时应返回退出代码。这篇文章描述了 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;
}
}
当没有挂起的线程时,应用程序会自动停止,而不会出现
exit()
。我遇到了同样的问题,最后我找到了发生这种情况的原因。我总是依赖 spring 机制,它会在应用程序退出时关闭所有 Closeable
beans,但它是在 JVM 关闭挂钩上调用的,因此在某些非守护线程运行之前永远不会调用它。我通过在CommandLineRunner
中手动关闭所有具有打开线程的bean解决了这个问题。不幸的是,它对于自动配置创建的所有 bean 也是必需的(例如 spring-data-elasticsearch
创建此类 bean)。
使用命令行运行程序时存在一个常见的陷阱。启动时:
<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中解释的那样)。