【问题标题】:Should the Spring Boot shutdown endpoint shut down the entire JVM process, or just the application context?Spring Boot 关闭端点应该关闭整个 JVM 进程,还是只关闭应用程序上下文?
【发布时间】:2023-03-17 06:58:01
【问题描述】:

我从 Spring Boot 的关闭端点收到 200 响应,我看到应用程序上下文按预期关闭,但随后 JVM 进程本身永远保持活动状态。这是关闭端点的预期行为,还是预期进程本身也会正常终止?

http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html 中,它表示关闭端点“允许应用程序正常关闭(默认情况下未启用)”。

【问题讨论】:

  • 您必须重新表述您的问题才能独立存在。询问您链接到的原始问题的人将看不到此帖子。不过,这里应该有一个可行的问题。

标签: spring-boot


【解决方案1】:

感谢 Stéphane,我找到了阻止 JVM 进程在到达 /shutdown 端点后终止的原因。我的一个依赖项中有一个 ScheduledExecutor 没有被应用程序上下文关闭,它阻止了 JVM 进程关闭(即使在应用程序上下文关闭之后)。我写了一个简单的例子来展示如何重现该行为,另一个例子展示了如何解决它。

当您点击 /shutdown 端点时,此示例不会终止 JVM 进程:

@SpringBootApplication
public class AppSpringConfiguration {

    public static void main(String[] args) {
        SpringApplication.run(AppSpringConfiguration.class);
    }

    @Bean
    public ClassWithExecutor ce() {
        return new ClassWithExecutor();
    }

    @PostConstruct
    public void startScheduledTask() {
        ce().startScheduledTask();
    }

    @RestController
    public static class BusinessLogicController {

        @RequestMapping(value = "/hi")
        public String businessLogic() {
            return "hi";
        }
    }            

    public static class ClassWithExecutor {
        ScheduledExecutorService es;

        ClassWithExecutor() {
            this.es = Executors.newSingleThreadScheduledExecutor();
        }

        public void startScheduledTask() {
            es.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Printing this every minute");
                }
            }, 0, 3, TimeUnit.SECONDS);
        }    
    }
}

通过添加一个关闭钩子,当应用程序上下文关闭时关闭 ScheduledExecutor,JVM 进程现在在到达 /shutdown 端点后终止:

@SpringBootApplication
public class AppSpringConfiguration {

    public static void main(String[] args) {
        SpringApplication.run(AppSpringConfiguration.class);
    }

    @Bean
    public ClassWithExecutor ce() {
        return new ClassWithExecutor();
    }

    @Bean
    ShutdownAction sa() {
        return new ShutdownAction(ce());
    }

    @PostConstruct
    public void startScheduledTask() {
        ce().startScheduledTask();
    }

    @RestController
    public static class BusinessLogicController {

        @RequestMapping(value = "/hi")
        public String businessLogic() {
            return "hi";
        }
    }

    public static class ShutdownAction implements ApplicationListener<ContextClosedEvent> {
        private ClassWithExecutor classWithExecutor;

        ShutdownAction(ClassWithExecutor classWithExecutor) {
            this.classWithExecutor = classWithExecutor;
        }

        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            classWithExecutor.shutdown();
        }
    }

    public static class ClassWithExecutor {
        ScheduledExecutorService es;

        ClassWithExecutor() {
            this.es = Executors.newSingleThreadScheduledExecutor();
        }

        public void startScheduledTask() {
            es.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Printing this every minute");
                }
            }, 0, 3, TimeUnit.SECONDS);
        }

        public void shutdown() {
            es.shutdownNow();
        }
    }
}

【讨论】:

    【解决方案2】:

    除了您的 Spring Boot 应用程序之外,您还有一些阻止 JVM 退出的东西。如果你没有,并且你有一个演示问题的示例项目,那么请创建一个问题,我们会看看。

    您可以使用 spring-boot-maven-plugin(从 1.3 开始),而不是使用关闭端点,它具有用于典型集成测试场景的 startstop 目标。

    【讨论】:

      【解决方案3】:

      如果你有一个计划的执行器正在运行,你应该指定销毁方法:

      @Bean(destroyMethod = "shutdown")
      

      【讨论】:

        猜你喜欢
        • 2016-07-20
        • 2015-12-24
        • 2017-03-05
        • 1970-01-01
        • 2020-09-22
        • 1970-01-01
        • 1970-01-01
        • 2023-04-10
        • 2023-03-25
        相关资源
        最近更新 更多