如何优雅地关闭SpringBoot应用程序?听我给你讲

麦洛 等级 478 1 0

前言

Hi,大家好,我是麦洛,今天来聊聊如何优雅地关闭SpringBoot应用程序,有需要交流的朋友,可以私信我或者加我微信:miloleex都可以哈

在我们日常开发中,我们如何启停服务?可能下面的命令在熟悉不过了。

ps -ef|grep 8888
kill -9 8888
./startup.sh ;tail -f ../logs/catalina.out

暴利美学式的启停服务真的安全吗?今天我们来了解如何安全、优雅地停止 Spring Boot 应用程序,而不会使任何当前处理的请求失败或不中断正在进行的事务。

什么是正常关机?

优雅和强制关闭是停止应用程序的两种方法。当应用程序运行时,在处理请求的过程中。我们都知道它会消耗各种资源、建立连接、持久化数据或处理事务等。当我们修复了某个bug或者需要发版时,就需要我们停止当前正在运行的应用程序,以便完成我们的工作。这时候,采取合适的手段就显得尤为重要。

为了说明这个现象,我们来举一个例子。我们生活中关闭计算机时。如果遇到未保存的文件或一些程序未关闭,windows会提示我们关机之前完成这些工作。如果我们强制关机,就会丢失一些我们想要的东西,同样的逻辑也适用于我们的应用程序。幸运的是,某些应用程序能够在重新启动时可以恢复任何未完成的任务。这样停止不会造成任何伤害。另一方面,对于某些应用程序,突然关闭可能会导致意外结果。例如,非常大的事务失败,或打开资源等。那么Spring Boot 应用程序我们如何优雅的关机,接下来我们一起来看看,微信搜一搜"爱写Bug的麦洛"公众号关注我,一起努力写Bug,哈哈

未启用正常关机

当我们停止正在运行的应用程序或进程时,底层操作系统会向进程发送终止信号。在没有启用任何优雅关闭机制的情况下,Spring Boot 应用程序将在收到信号后立即终止。

为了演示这种行为,让我们编写一个 Controller 端点,它在返回之前需要更长的时间。或者,我们可以简单地让线程休眠相当长的时间,以便我们有机会在请求处理过程中停止应用程序。

@PostMapping("/students")
public void test(@RequestBody Student student) {
    log.info("新请求新增一个学生");
    studentService.addStudent(student);
    log.info("新增学生成功");
}

首先,我们将启动应用程序并向该端点执行请求。之后,一旦请求开始处理,我们将尝试停止应用程序。最后,我们将观察日志。

11:04:44|INFO | o.s.w.s.DispatcherServlet:547 - Completed initialization in 33 ms
11:04:44|INFO | c.a.s.t.s.w.StudentController:38 - 新请求新增一个学生
11:04:53|INFO | o.s.s.c.ThreadPoolTaskExecutor:218 - Shutting down ExecutorService 'applicationTaskExecutor'
11:04:53|INFO | c.z.h.HikariDataSource:350 - HikariPool-1 - Shutdown initiated...
11:04:53|INFO | c.z.h.HikariDataSource:352 - HikariPool-1 - Shutdown completed.

日志表明在 POST 请求完成之前,我们尝试关闭应用程序。从日志中可以明显看出,应用程序在没有等待请求完成就突然停止。

启用正常关机

Spring Boot 支持自动配置的优雅关机,配置非常简单。下一个配置片段显示了如何在 Spring Boot 中启用优雅关闭。

yaml文件:

server:
  shutdown: graceful

属性文件:

server.shutdown=graceful

启用此功能后,Spring Boot 将在完全关闭应用程序上下文之前等待当前请求完成。此外,在关闭阶段,它将停止接受新请求。Spring Boot 的所有嵌入式服务器都支持优雅终止。但是,拒绝新请求的方式可能会因各个服务器的实现而异。

这里演示如何在停止 Spring Boot 应用程序之前允许当前正在运行的 HTTP 请求完成。现在我们已经启用了正常关闭,我们将重新运行控制器端点并尝试在请求完成之前停止应用程序。

@PostMapping("/students")
public void test(@RequestBody Student student) {
    log.info("新请求新增一个学生");
    studentService.addStudent(student);
    log.info("新增学生成功");
}

让我们执行 POST 端点,并立即停止应用程序

14:14:57|INFO | c.a.s.t.s.w.StudentController:38 - 新请求新增一个学生
14:14:58|INFO | o.s.b.w.e.t.GracefulShutdown:53 - Commencing graceful shutdown. Waiting for active requests to complete
14:15:07|INFO | c.a.s.t.s.w.StudentController:40 - 新增学生成功
14:15:07|INFO | o.s.b.w.e.t.GracefulShutdown:78 - Graceful shutdown complete
14:15:07|INFO | o.s.s.c.ThreadPoolTaskExecutor:218 - Shutting down ExecutorService 'applicationTaskExecutor'
14:15:07|INFO | c.z.h.HikariDataSource:350 - HikariPool-1 - Shutdown initiated...
14:15:07|INFO | c.z.h.HikariDataSource:352 - HikariPool-1 - Shutdown completed.

从日志中可以看出,在调用后立即收到了关闭信号。但是,Spring Boot 仍然允许在完全停止应用程序上下文之前完成请求。

正常关机超时

在正常关闭期间,Spring Boot 允许应用程序在一些宽限期内完成所有当前请求或进程。一旦宽限期结束,未完成的进程或请求就会被终止。默认情况下,Spring Boot 允许 30 秒的正常关闭超时。但是,我们可以使用应用程序属性或 Yaml 文件对其进行配置。

yaml文件:

spring:
  lifecycle:
    timeout-per-shutdown-phase: "10s"

属性文件:

spring.lifecycle.timeout-per-shutdown-phase=10s

不同嵌入式 Web 服务器优雅停机行为区别?

容器停机行为取决于具体的 web 容器行为

web 容器名称 行为说明
Tomcat 9.0.33+ 停止接受网络层的请求,客户端新请求等待超时。
Reactor Netty 停止接受网络层的请求,客户端新请求等待超时。
Undertow 接受请求,客户端新请求直接返回 503。
Jetty 停止接受网络层的请求,客户端新请求等待超时。

特别说明

官网中有这样一段说明,如果你的IDE无法正确发送SIGTERM信号,可能无法在本地测试

如何优雅地关闭SpringBoot应用程序?听我给你讲

总结

在上文中,我们学习了如何优雅地关闭Spring Boot 应用程序。配置启用正常关闭后,Spring Boot 允许应用程序在完全停止应用程序之前完成任何正在进行的请求或进程。此外,它可以防止任何新请求到达应用程序。而且允许在 30 秒的默认宽限期内完成正在进行的请求。但是,我们可以更改此设置以指定自定义超时值或宽限期。

收藏
评论区

相关推荐

Spring Cloud 微服务开发指南
如同 Spring Boot 在 Java Web 开发领域中的统治地位,Spring Cloud 在 Java 微服务应用开发领域中同样处于垄断地位。软件系统从单体升级到微服务架构,随之会出现各种分布式系统所特有的问题,包括服务注册发现、认证授权、限流熔断、调用追踪等。Spring Cloud 提供了各种组件来解决这些问题,本文将通过升级改造一个单体 AP
Spring Boot API 服务测试指南
Spring Boot 除了简化了 Spring 应用的开发,同时也简化了 Spring 应用的测试。它内置支持各种常用测试工具,包括 Spring Test、JUnit、TestNG、Mockito、AssertJ 等。本文将讲解如何编写单元测试和集成测试来保障 Spring Boot API 应用不同层级代码的质量,其中会涉及到使用嵌入式的 H2 数据库
Spring Boot API 服务开发指南
Spring Boot 大大简化了使用 Spring 框架开发 Web 应用时的配置工作,使用它只需添加相关依赖包,即可通过零配置或少量配置来运行一个 Web 应用。本文将使用 Spring Boot 来开发一个 API 服务,同时支持 REST 和 GraphQL 两种协议。内容包括使用 Querydsl 来替换 JPQL 以便以类型安全的方式动态构建 S
浅析Spring boot与Spring cloud 之间的关系
浅析Spring boot与Spring cloud 之间的关系 20180515 18:16:10有些童鞋刚接触这块 ,理解不是很深刻会经常问道这样类似的问题,下面我就简单讲解一下Spring boot与Spring cloud 之间的关系!Spring boot 是 Spring 的一
优雅关闭Spring Boot应用
最新的Spring Boot添加了一个新特性 优雅停机。 官方介绍官方文档地址:https://docs.spring.io/springboot/docs/current/reference/htmlsingle/bootfeaturesgracefulshutdown 这个机制会有一个超时时间,该超时时间提供一个宽限期,在此宽限期内,现有请求将被允
SpringBoot整合Mybatis连接Oracle数据库
学习目标:<font colorred face"宋体" size3通过本篇文章掌握如何使用SpringBoot整合Mybatis来连接Oracle数据库进行基本的数据库操作。在之前的项目中,大多使用的是Mysql数据库,但在企业中使用的是Oracle数据库,下面就来简单的介绍下如何使用SpringBoot整合Mybatis的方式操作Oracle数据库。<
Element 'configuration' cannot have character [children], because the type's content type is element-only.
整合springboot+mybatis时copy网上的配置,然后报错了。 <configuration        <! mybatis用于生成代码的配置文件   <configurationFilesrc/main/resources/gener
Java开发学习路线,看完这篇就够了
Java 开发,我们应该从哪里开始学?应该学习哪些东西?应该按照什么样的顺序来学?Java 开发涉及到的领域非常多,对于开发者而言要掌握的东西也非常多,初入行的小伙伴甚至觉得这些要掌握的东西非常杂乱,其实不然!所有要学习的东西都是有内在关联的。大仙今天就来和大家捋一捋 Java 学习路线图,一起来看看都有哪些东西需要掌握,以及要按照什么样的顺序来学习。](h
springBoot集成redis
Redis作为一个Java后端面试中的一个常问考点,并且在项目中越来越常用,所以自己动手搭建了一个基于springboot集成redis做为数据缓存的demo(springboot集成mybatis、redis,并具有增删改查询接口)。关注微信公众号【菜鸟阿都】并回复:redis,可获得源码。后面也会继续深入研究redis相关知识,期待与大家一起学习交流。r
想搞定大厂面试官?被逼无奈开始狂啃底层技术
Part 1微服务架构设计概述1.1 传统应用架构的问题1.2 微服务架构是什么1.3 微服务架构有哪些特点和挑战1.4 如何搭建微服务架构 Part 2微服务开发框架2.1 Spring Boot 是什么2.2 如何使用Spring Boot框架2.3 Spring Boot生产级特性 Part 3微服务网关3.1 Node.js 是什么3.2 如何使用
重磅!这份笔记连阿里P8面试官都说太详细了
一、Spring Boot 相关(1)SpringBoot 面试专题 什么是 Spring Boot? Spring Boot 有哪些优点? 什么是 JavaConfig? 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器? Spring Boot 中的监视器是什么? 如何在 Spring Boot 中禁用 Act
面试官突击一问:深入理解mysql技术
京东Java研发岗一面(基础面,约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和springboot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作用范围? 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较? Java线程池的原理?线程池有哪些?线程池
最新2021年Java大厂面试经验,赶紧学起来
内容简介: 本书一共15章,核心内容为SpringBoot、SpringCloud、Docker、RabbitMQ消息组件。其中,SpringBoot是SpringMVC技术的延伸,使用它进行程序开发会更简单,服务整合也会更容易。SpringCloud是当前微架构的核心技术方案,属于SpringBoot的技术延伸,它可以整合云服务,基于RabbitMQ和 G
如何优雅地关闭SpringBoot应用程序?听我给你讲
前言Hi,大家好,我是麦洛,今天来聊聊如何优雅地关闭SpringBoot应用程序,有需要交流的朋友,可以私信我或者加我微信:miloleex都可以哈在我们日常开发中,我们如何启停服务?可能下面的命令在熟悉不过了。shellps ef|grep 8888kill 9 8888./startup.sh ;tail f ../logs/catalina.out暴利