以编程方式关闭Spring Boot应用程序


109

如何在不终止VM的情况下以编程方式关闭Spring Boot应用程序?

在其他作品中,

new SpringApplication(Main.class).run(args);

1
好点子!调用close()应该可以完成这项工作。
Axel Fontaine 2014年


@AnandVarkeyPhilips不,绝对不是。这是关于一个API,另一个是关于操作的一种方式。
Axel Fontaine

好的,该问题链接可能会对他人有所帮助。您要我删除以上评论吗?
Anand Varkey Philips飞利浦

Answers:


111

关闭a 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);
    }
}

1
如果我使用ctx.close(); 不需要在结尾处调用System.exit(n)吗?上下文close()应该在其中包含System.exit()?
否认

2
@Denys否,上下文在关闭时不会退出Java进程。我的示例中的出口仅演示如何ExitCodeGenerator使用。您可以从main方法中返回以正常退出(退出代码0)。
Sotirios Delimanolis

78

在Spring Boot应用程序中,您可以使用类似以下的内容

ShutdownManager.java

import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;

@Component
class ShutdownManager{

    @Autowired
    private ApplicationContext appContext;

    public void initiateShutdown(int returnCode){
        SpringApplication.exit(appContext, () -> returnCode);
    }
}

16
支持显示ApplicationContext可以自动将其注入其他bean的投票。
安东尼·楚纳德

1
@snovelli如何调用启动关机方法?initialShutdown(x),x = 0吗?
StackOverFlow

有条件关闭时,可以执行此操作。SpringApplication.run(..)。close()将在程序完成时执行。
Abubacker Siddik

为什么是SpringApplication。(appContext,()-> returnCode); 为什么appContext.close()无法。有什么区别 ?
公羊

@StackOverFlow您需要在需要的地方注入bean,然后按照建议的方式传递返回代码(x = 0)(如果它已正确关闭)。例如,您可以将Shutdown Manager注入RestController并允许远程关机,也可以将其注入到Healthcheck监视中,以在丢失下游服务的情况下关闭JVM
snovelli

36

这项工作,甚至完成打印。

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");

所以加.close()run()

说明:

public ConfigurableApplicationContext run(String... args)

运行Spring应用程序,创建并刷新一个新的ApplicationContext。参数:

args -应用程序参数(通常从Java main方法传递)

返回: 运行中的ApplicationContext

和:

void close()关闭此应用程序上下文,释放实现可能持有的所有资源和锁。这包括销毁所有缓存的单例bean。注意:不会在父上下文上调用关闭;父级上下文具有自己的独立生命周期。

可以多次调用此方法,而不会产生副作用:在已经关闭的上下文上进行的后续关闭调用将被忽略。

因此,基本上,它不会关闭父上下文,这就是VM不退出的原因。


2
提醒一下,此解决方案适用于批处理之类的短暂过程,但请勿在Spring MVC应用程序上使用。引导后,应用程序刚刚关闭。
Michael COLL

@MichaelCOLL问题是关于如何以编程方式关闭Spring Boot应用程序,而不管其类型如何。它还适用于Spring MVC
ACV

1
@ACV你是对的,它很好用。但是对于我认为必须保持正常运行的应用程序(例如Spring MVC应用程序)来说,这不是一个好方法。就我而言,我使用了SpringApplication.exit(appContext, () -> returnCode)
Michael COLL

1
您在最后一行中指的是什么VM?如果您使用来启动Spring Boot应用程序SpringApplication.run(MyApplication.class, args),则没有父上下文。仅有一个上下文,该上下文是由创建和返回的run,然后您可以立即进行创建close。@迈克尔是正确的。这对于大多数在Spring初始化后需要执行任何操作的程序不起作用。
救主

@Savior JVM。有一个父上下文。在这里,我们讨论的是如何关闭Spring Boot应用程序。您通常不会以这种方式关闭Web应用程序。因此,此机制通常用于短期应用程序,这些应用程序需要执行一些操作然后需要停止。默认情况下,即使您完成了批处理,Spring Boot仍将继续运行,因此您将可以使用此机制。
ACV

3

在应用程序中,您可以使用SpringApplication。它有一个带有exit()两个参数的静态方法:the ApplicationContext和an 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 {
...

好。我应该在哪里获得ExecutorServiceExitCodeGenerator?如果是Bean,可以显示创建摘要代码(以及从哪个类创建)吗?应该将方法shutdownDown(ExecutorServiceExitCodeGenerator exitCodeGenerator)放在哪个类中?
弗拉德·G.19年

2

这将确保正确启动SpringBoot应用程序,并将资源释放回操作系统,

@Autowired
private ApplicationContext context;

@GetMapping("/shutdown-app")
public void shutdownApp() {

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.