Java 以编程方式关闭Spring启动应用程序

Java 以编程方式关闭Spring启动应用程序,java,spring,spring-boot,Java,Spring,Spring Boot,如何在不终止VM的情况下以编程方式关闭春季启动应用程序 在其他作品中,与之相反的是什么 new SpringApplication(Main.class).run(args); 关闭a基本上意味着关闭底层的ApplicationContext。该方法将ApplicationContext作为ConfigurableApplicationContext提供给您。然后你可以自己做 比如说, @SpringBootApplication public class Example { publ

如何在不终止VM的情况下以编程方式关闭春季启动应用程序

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

new SpringApplication(Main.class).run(args);
关闭a基本上意味着关闭底层的
ApplicationContext
。该方法将
ApplicationContext
作为
ConfigurableApplicationContext
提供给您。然后你可以自己做

比如说,

@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();
    }
}
@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);
    }
}
或者,您可以使用
static
helper方法为您执行此操作。比如说,

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

这件作品,即使完成了也要印刷

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");
因此,在
run()之后添加
.close()

说明:

public ConfigurableApplicationContext运行(字符串…参数)

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

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

返回: 正在运行的应用程序上下文

以及:

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

此方法可多次调用,且无副作用: 对已关闭上下文的后续关闭调用将被忽略


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

最简单的方法是在需要启动关闭的位置注入以下对象

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

在应用程序中可以使用
SpringApplication
。这有一个静态的
exit()
方法,它接受两个参数:
ApplicationContext
ExitCodeGenerator

i、 e.您可以声明此方法:

@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}
在集成测试中您可以通过在类级别添加
@DirtiesContext
注释来实现:

  • @DirtiesContext(classMode=classMode.AFTER\u CLASS)
    -关联的ApplicationContext将在测试类之后标记为dirty
  • @DirtiesContext(classMode=classMode.AFTER\u EACH\u TEST\u METHOD)
    -在类中的每个测试方法之后,关联的应用程序上下文将标记为dirty
i、 e


这将确保SpringBoot应用程序被正确关闭,资源被释放回操作系统

@Autowired
private ApplicationContext context;

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

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}

说得好!调用close()就可以了。可能是@AnandVarkeyPhilips的副本不,肯定不是。这一个是关于API的,另一个是关于ops这样做的方法。好的。。这个问题链接可能会帮助其他人。您想让我删除上面的注释吗?赞成显示
ApplicationContext
可以自动注入到其他bean中。@snovelli如何调用initiate shutdown方法?initiateShutdown(x),x=0?当有条件关闭时,可以执行此操作。SpringApplication.run(..).close()将在程序完成时执行。为什么选择SpringApplication。(appContext,()->returnCode);为什么不能使用appContext.close()。区别是什么?@StackOverFlow您需要在需要的地方注入bean,然后按照您的建议传递返回代码(x=0),如果它正确关闭。例如,您可以将shutdownmanager注入RestController并允许远程关机,或者您可以将它注入healthcheck监控中,以便在缺少下游servicesOk时关闭JVM。我应该在哪里获得ExecutorServiceExitCodeGenerator?如果它是一个bean,您可以显示创建代码段代码(以及它是从哪个类创建的)吗?方法shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator)应该放在哪个类中?如果我使用ctx.close();不需要呼叫系统。在右端退出(n)?context close()应该包含System.exit()。@Denys否,关闭时上下文不会退出java进程。我的示例中的exit只是演示了如何使用
ExitCodeGenerator
。您可以从
main
方法返回以优雅地退出(退出代码0)。只需提醒一下,此解决方案适用于批处理这样的短期流程,但不要在Spring MVC应用程序上使用。应用程序在启动后刚刚关闭。@MichaelCOLL问题是关于如何以编程方式关闭spring boot应用程序,而不考虑其类型。它也适用于春季MVC@ACV你说得对,它很管用,很管用。但是对于一个必须保持状态的应用程序(比如SpringMVC应用程序),我认为,这不是一个好方法。在我的例子中,我使用了
SpringApplication.exit(appContext,()->returnCode)
。您在最后一行中指的是什么VM?如果您使用
SpringApplication.run(MyApplication.class,args)
启动Spring引导应用程序,则没有父上下文。只有一个上下文,即由
run
创建并返回的上下文,然后立即
关闭该上下文@迈克尔是对的。这对于在Spring上下文初始化后需要执行任何操作的程序都不起作用,而Spring上下文是大多数程序的基础。@Savior JVM。有一个父上下文。这里我们讨论的是如何关闭Spring启动应用程序。您通常不会以这种方式关闭web应用程序。因此,这种机制通常用于执行某些操作然后需要停止的短期应用程序。默认情况下,即使在完成批处理之后,SpringBoot仍将继续运行,因此您可能希望使用此机制!根据需要,在我的应用程序中退出System.exit(exitCode)
,否则将重新启动spring引导