【问题标题】:Programmatically shut down Spring Boot application以编程方式关闭 Spring Boot 应用程序
【发布时间】:2014-05-21 13:39:02
【问题描述】:

如何以编程方式关闭 Spring Boot 应用程序不终止 VM

在其他作品中,什么是相反的

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

【问题讨论】:

  • 好点!调用 close() 应该可以完成这项工作。
  • @AnandVarkeyPhilips 不,绝对不是。一个是关于 API,另一个是关于操作的一种方式。
  • 好的.. 该问题链接可能对其他人有所帮助。要我删除上面的评论吗?

标签: java spring spring-boot


【解决方案1】:

关闭SpringApplication 基本上意味着关闭底层ApplicationContextSpringApplication#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);
    }
}

【讨论】:

  • 如果我使用 ctx.close();最后不需要调用 System.exit(n) 吗? context close() 里面应该有 System.exit() 吗?
  • @Denys 不,上下文不会在关闭时退出 java 进程。我的示例中的出口只是演示了如何使用ExitCodeGenerator。您可以从 main 方法返回以优雅退出(退出代码 0)。
【解决方案2】:

最简单的方法是在需要启动关机的地方注入以下对象

ShutdownManager.java

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

@Component
class ShutdownManager {

    @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);
    }
}

【讨论】:

  • 赞成 ApplicationContext 可以自动注入其他 bean。
  • @snovelli 如何调用启动关机方法?启动关机(x) , x=0 ?
  • 有条件关闭时,可以执行这个。 SpringApplication.run(..).close() 将在程序完成时执行。
  • 为什么是 SpringApplication.(appContext, () -> returnCode);为什么不能 appContext.close()。有什么区别?
  • @StackOverFlow 您需要将 bean 注入您需要的地方,然后按照您的建议 (x=0) 传递返回码(如果它正确关闭)。例如,您可以将 Shutdown Manager 注入 RestController 并允许远程关闭,或者您可以将其注入运行状况检查监控,以在缺少下游服务的情况下关闭 JVM
【解决方案3】:

这行得通,即使完成也会被打印出来。

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

所以在run()之后添加.close()

解释:

public ConfigurableApplicationContext run(String... args)

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

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

返回: 一个正在运行的 ApplicationContext

和:

void close()关闭这个应用上下文,释放所有资源 和实现可能持有的锁。这包括破坏 所有缓存的单例 bean。注意:不会在父对象上调用 close 语境;父上下文有自己独立的生命周期。

这个方法可以被多次调用而没有副作用: 对已关闭上下文的后续关闭调用将被忽略。

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

【讨论】:

  • 提醒一下,这个解决方案适用于像批处理这样的短期过程,但不要在 Spring MVC 应用程序上使用它。应用程序在启动后刚刚关闭。
  • @MichaelCOLL 问题是关于如何以编程方式关闭 Spring Boot 应用程序,而不管其类型如何。它也适用于 Spring MVC
  • @ACV 没错,它可以工作,它工作得很好。但是对于必须保持运行的应用程序(例如 Spring MVC 应用程序),我认为这不是这样做的好方法。就我而言,我使用了SpringApplication.exit(appContext, () -> returnCode)
  • 您在最后一行中指的是什么虚拟机?如果您使用 SpringApplication.run(MyApplication.class, args) 启动 Spring Boot 应用程序,则没有父上下文。只有一个上下文,由run 创建和返回的上下文,然后您立即close。 @Michael 是对的。这不适用于在 Spring 上下文初始化后需要执行任何操作的程序,这是大多数程序。
  • @Savior JVM。有一个父上下文。在这里,我们正在讨论如何关闭 Spring Boot 应用程序。您通常不会以这种方式关闭 Web 应用程序。因此,这种机制通常用于执行某些操作然后需要停止的短期应用程序。默认情况下,即使在您完成批处理之后,Spring boot 也会继续运行,因此您需要使用此机制。
【解决方案4】:

这将确保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 正在重新启动
【解决方案5】:

在应用程序中您可以使用SpringApplication。这有一个静态的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 {
...

【讨论】:

  • 好的。我应该在哪里获得 ExecutorServiceExitCodeGenerator?如果是 bean,能否显示创建 sn-p 代码(以及它是从哪个类创建的)?方法shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator)应该放在哪个类中?
猜你喜欢
  • 2017-02-24
  • 2014-12-20
  • 1970-01-01
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
相关资源
最近更新 更多