我如何以编程方式关闭一个Spring Boot应用程序,而不终止VM?
换句话说,什么是相反的操作?
new SpringApplication(Main.class).run(args);
我如何以编程方式关闭一个Spring Boot应用程序,而不终止VM?
换句话说,什么是相反的操作?
new SpringApplication(Main.class).run(args);
关闭一个SpringApplication
,基本上意味着关闭底层的ApplicationContext
。方法SpringApplication#run(String...)
将该ApplicationContext
作为ConfigurableApplicationContext
提供给您。然后您可以自行关闭它(close())
。
例如,
@SpringBootApplication
public class Example {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
// ...determine it's time to shut down...
ctx.close();
}
}
或者,您可以使用static
SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)
辅助方法来为您完成。例如,
@SpringBootApplication
public class Example {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
// ...determine it's time to stop...
int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
@Override
public int getExitCode() {
// no errors
return 0;
}
});
// or shortened to
// int exitCode = SpringApplication.exit(ctx, () -> 0);
System.exit(exitCode);
}
}
最简单的方法是在需要启动关闭的地方注入以下对象
ApplicationShutdownManager.java
import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;
@Component
class ApplicationShutdownManager {
@Autowired
private ApplicationContext appContext;
/*
* Invoke with `0` to indicate no error or different code to indicate
* abnormal exit. es: shutdownManager.initiateShutdown(0);
**/
public void initiateShutdown(int returnCode){
SpringApplication.exit(appContext, () -> returnCode);
}
}
这个有效,即使已经打印出来。
SpringApplication.run(MyApplication.class, args).close();
System.out.println("done");
在run()
方法后添加.close()
。
public ConfigurableApplicationContext run(String... args)
运行Spring应用程序,创建并刷新新的ApplicationContext。参数:
args
- 应用程序参数(通常从Java main方法传递)返回值: 正在运行的ApplicationContext
基本上,它不会关闭父上下文,这就是为什么VM不退出的原因。
void close()
关闭此应用程序上下文,释放实现可能持有的所有资源和锁定。这包括销毁所有缓存的单例bean。注意:不会在父上下文上调用close;父上下文具有它们自己的独立生命周期。可以多次调用此方法而没有副作用: 对于已经关闭的上下文的后续关闭调用将被忽略。
SpringApplication.exit(appContext, () -> returnCode)
。 - Michaël COLLSpringApplication.run(MyApplication.class, args)
启动你的Spring Boot应用程序,那么就没有父上下文。只有一个上下文,即由run
创建和返回的上下文,然后你立即将其关闭。@Michael是正确的。这对于需要在Spring上下文初始化后执行任何操作的程序(大多数程序)是不起作用的。 - Saviorrun
创建了一个单独的 ApplicationContext
,没有任何层次结构。无论它是 Web 应用程序还是其他应用程序,在关闭该上下文时,将销毁其 bean(并关闭线程池),并且假设程序除与上下文无关的其他事情外不执行任何其他操作,则会退出。我认为 @MichaelCOLL
的观点是,最好捕获由 run
返回的上下文,并在准备退出应用程序时基于某些辅助信号调用 close
。 - Savior这将确保SpringBoot应用程序被正确关闭并释放资源回到操作系统中,
@Autowired
private ApplicationContext context;
@GetMapping("/shutdown-app")
public void shutdownApp() {
int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
System.exit(exitCode);
}
System.exit(exitCode)
,否则Spring Boot将会重新启动。 - Jonas DSpringApplication
。它有一个静态的exit()
方法,接受两个参数: ApplicationContext
和ExitCodeGenerator
:@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
SpringApplication.exit(applicationContext, exitCodeGenerator);
}
@DirtiesContext
注释来实现:
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
- 在测试类之后,关联的ApplicationContext将被标记为脏状态。@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
- 在类中的每个测试方法之后,关联的ApplicationContext将被标记为脏状态。@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class},
webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"server.port:0"})
@DirtiesContext(classMode= DirtiesContext.ClassMode.AFTER_CLASS)
public class ApplicationIT {
...