Spring Boot 应用优雅停机与资源清理:深入理解关闭钩子

在开发和部署 Spring Boot 应用程序时,除了关注其启动和运行,理解如何实现**优雅停机(Graceful Shutdown)**也同样至关重要。优雅停机意味着在应用程序关闭时,能够有序地释放资源、完成正在进行的任务,并避免数据丢失或损坏。本文将深入探讨 Spring Boot 中与优雅停机相关的机制,特别是 JVM 关闭钩子以及如何自定义清理逻辑。

1. 什么是 Spring Boot 的关闭钩子?

在 Spring Boot 应用程序的启动过程中,你可能会注意到类似以下的代码片段(通常在 SpringApplication.class 中):

// ... existing code ...
if (this.properties.isRegisterShutdownHook()) {SpringApplication.shutdownHook.enableShutdownHookAddition();
}
// ... existing code ...

这段代码的核心在于 this.properties.isRegisterShutdownHook()。它对应于 Spring Boot 配置中的 spring.main.register-shutdown-hook 属性。

  • spring.main.register-shutdown-hook: 这个配置属性(默认为 true)决定了 Spring Boot 应用程序是否会在 JVM 启动时注册一个关闭钩子(Shutdown Hook)
  • SpringApplication.shutdownHook.enableShutdownHookAddition(): 当 spring.main.register-shutdown-hooktrue 时,此方法会被调用,它负责向 JVM 运行时环境注册一个钩子。当 JVM 接收到外部的关闭信号(如 Ctrl+Ckill <pid> 命令等,而非强制终止的 kill -9)时,这个钩子就会被激活。

简而言之,注册关闭钩子的目的是让 Spring Boot 有机会在 JVM 正常关闭前,执行一系列预定义的清理操作,从而确保应用程序的优雅停机。 这些操作可能包括关闭数据库连接池、释放文件句柄、停止后台线程等。

2. 如何自定义关闭时的清理逻辑?

Spring Boot 提供了灵活的机制来允许开发者在应用程序关闭时执行自定义的清理逻辑。主要有两种常用且推荐的方式:监听 ContextClosedEvent 和使用 @PreDestroy 注解。

2.1 监听 ContextClosedEvent

这是最推荐的方式,因为它与 Spring 应用程序上下文的生命周期事件紧密集成。当 Spring 应用程序上下文完成其所有 Bean 的销毁并准备关闭时,会发布 ContextClosedEvent

如何定义:

  1. 创建一个实现 org.springframework.context.ApplicationListener<ContextClosedEvent> 接口的类。
  2. onApplicationEvent 方法中编写你的全局清理逻辑。
  3. 使用 @Component 注解将其注册为 Spring Bean。

示例:

// src/main/java/com/dosun/demo01/listener/MyCleanupListener.java
package com.dosun.demo01.listener;import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;@Component
public class MyCleanupListener implements ApplicationListener<ContextClosedEvent> {@Overridepublic void onApplicationEvent(ContextClosedEvent event) {System.out.println("应用程序上下文已关闭。执行自定义清理逻辑...");// 在这里编写你的自定义清理逻辑,例如:// 1. 关闭数据库连接// 2. 释放文件句柄// 3. 停止线程池// 4. 清理缓存等System.out.println("自定义清理逻辑执行完毕。");}
}

当应用程序正常关闭时,onApplicationEvent 方法会被调用,从而执行你在其中定义的清理代码。

2.2 使用 @PreDestroy 注解

对于 Spring 容器管理的特定 Bean,你可以使用 @PreDestroy 注解来标记一个方法。这个方法会在该 Bean 被销毁之前执行。这对于 Bean 级别的资源清理非常有用。

如何定义:

在任何 Spring 管理的 Bean 中,在你希望执行 Bean 特定清理逻辑的方法上添加 @PreDestroy 注解。

示例:

package com.dosun.demo01.service;import org.springframework.stereotype.Service;
import jakarta.annotation.PreDestroy;@Service
public class MyService {public MyService() {System.out.println("MyService Bean 已创建。");}@PreDestroypublic void cleanup() {System.out.println("MyService Bean 即将被销毁。执行 Bean 级别的清理逻辑...");// 在这里编写 MyService 特定的清理逻辑,例如关闭 MyService 内部的连接System.out.println("MyService Bean 级别的清理逻辑执行完毕。");}public void doSomething() {System.out.println("MyService 正在执行一些操作。");}
}

2.3 如何选择?

  • ContextClosedEvent: 适用于需要在整个应用程序关闭时执行的全局清理任务。它在所有 Bean 都被销毁之后,但在 JVM 真正退出之前执行。例如,全局的日志系统清理、一些共享资源的释放等。
  • @PreDestroy: 适用于特定 Bean 的清理任务。它在该 Bean 被销毁之前执行。例如,某个 Bean 内部持有的数据库连接、线程池、文件句柄等资源的释放。

在大多数情况下,监听 ContextClosedEvent 会是更灵活和通用的选择,因为你可以在一个地方集中管理所有应用程序级别的关闭逻辑。

3. spring.main.register-shutdown-hookfalse 的影响

现在我们来讨论一个关键问题:如果 spring.main.register-shutdown-hook 被设置为 false,清理钩子是不是就不生效了?

答案是:是的,在大多数情况下,自定义的清理钩子将不会生效,或者说无法在应用程序接收到正常关闭信号时被优雅地触发。

具体影响如下:

  • 对于监听 ContextClosedEvent 的自定义清理逻辑:
    如果 spring.main.register-shutdown-hookfalse,Spring Boot 将不会向 JVM 注册关闭钩子。这意味着当 JVM 收到 Ctrl+Ckill <pid> 等正常的关闭信号时,Spring Boot 应用程序将无法通过其内部的关闭钩子机制来优雅地关闭 Spring 应用程序上下文。因此,你的 MyCleanupListener 中监听 ContextClosedEventonApplicationEvent 方法将不会被触发

  • 对于使用 @PreDestroy 注解的方法:
    @PreDestroy 注解的方法是在 Spring Bean 被销毁之前调用的,这是 Spring 容器生命周期的一部分。

    • 如果 Spring 应用程序上下文能够被正常关闭(例如,你在代码中手动调用了 SpringApplication.exit()ApplicationContext.close()),那么即使 spring.main.register-shutdown-hookfalse@PreDestroy 方法仍然会被调用。
    • 但是,在通常的场景下,如果 spring.main.register-shutdown-hookfalse,并且你期望通过操作系统信号(如 Ctrl+C)来关闭应用程序,那么 JVM 不会通知 Spring 执行其关闭逻辑。Spring 容器就无法执行其正常的销毁流程,包括调用 @PreDestroy 方法。应用程序可能会突然终止,导致资源未释放,数据不一致等问题。

总结来说:

spring.main.register-shutdown-hook 配置是 Spring Boot 实现应用程序优雅停机的关键。

  • 如果设置为 true(默认值且推荐):Spring 会注册 JVM 关闭钩子,确保在应用程序因外部信号而关闭时,ContextClosedEvent 监听器和 @PreDestroy 方法都能得到执行,从而进行必要的清理。
  • 如果设置为 false:Spring 将不会注册这个 JVM 关闭钩子。这意味着当应用程序收到 Ctrl+Ckill 等信号时,Spring 应用程序上下文将不会被优雅关闭。那些依赖 Spring 正常关闭流程的清理逻辑(包括 ContextClosedEvent 和通常情况下的 @PreDestroy)将不会生效。这可能导致应用程序资源未释放、数据不一致等问题。

因此,在大多数生产环境中,强烈建议将 spring.main.register-shutdown-hook 保持为 true,以确保应用程序能够以健壮和可靠的方式关闭并清理资源。这将极大地提高应用程序的稳定性和数据完整性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91749.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91749.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

淘宝扭蛋机小程序开发:重构电商娱乐化体验的新范式

在电商行业同质化竞争加剧的当下&#xff0c;消费者对购物体验的期待已从“功能满足”转向“情感共鸣”。淘宝扭蛋机小程序凭借“盲盒式随机奖励游戏化交互”的创新模式&#xff0c;成为撬动年轻用户消费力的新支点。其开发逻辑不仅是对传统电商的升级&#xff0c;更是对“娱乐…

YOLO演变史(一)

在YOLOV1发布后&#xff0c;作者并没有满足于此&#xff0c;而是持续对YOLO进行了改进。 YOLOV2&#xff1a;Better, Faster, Stronger YOLOv2&#xff08;又称YOLO9000&#xff09;发表于2017年CVPR&#xff0c;是YOLO系列的第二代版本。其论文标题“Better, Faster, Stronger…

专题:2025智能体研究报告|附70份报告PDF、原数据表汇总下载

原文链接&#xff1a;https://tecdat.cn/?p43035 智能体正在改写商业规则&#xff1a;某城商行的智能客服用公有云部署&#xff0c;把单笔交互成本从5.7元砍到1.2元&#xff0c;投诉率直降42%&#xff08;《赛迪智库&#xff1a;2025全球智能体进展报告》P24&#xff09;&…

Axios 完整功能介绍和完整示例演示

Axios 是一个基于 Promise 的现代化 HTTP 客户端库&#xff0c;用于浏览器和 Node.js 环境。它提供了简洁的 API 和强大的功能&#xff0c;是前端开发中最常用的网络请求工具之一。核心功能 浏览器 & Node.js 双平台支持 浏览器中使用 XMLHttpRequestNode.js 中使用 http 模…

math.h函数

math.c函数作用 1. 基本三角函数&#xff08;参数为弧度&#xff09; sin(double x)&#xff1a;计算正弦值。cos(double x)&#xff1a;计算余弦值。tan(double x)&#xff1a;计算正切值。asin(double x)&#xff1a;反正弦&#xff08;返回值范围&#xff1a;[-π/2, π/2]&…

在Next.js里玩转pdf预览

1.背景在项目开发中&#xff0c;pdf预览是一个很常见的业务。各大公司为了保护自己的知识产权&#xff0c;也会对pdf预览进行限制&#xff0c;比如&#xff1a;不允许下载、打印&#xff0c;不允许提取文字等等。要想在实现预览功能的基础上还要附加这些限制&#xff0c;有很多…

算法竞赛备赛——【图论】求最短路径——Floyd算法

floyd算法 基于动态规划 应用&#xff1a;求多源最短路 时间复杂度&#xff1a;n^3 dijkstra&#xff1a;不能解决负边权 floyd&#xff1a;能解决负边权 不能解决负边权回路问题 求最短路径&#xff1a;dijkstra bfs floyd 思路 1.让任意两点之间的距离变短&#xff1a;引入…

双指针(滑动窗口)相关算法题

双指针算法有时候也叫尺取法或者滑动窗口&#xff0c;是⼀种优化暴力枚举策略的手段&#xff1a;当我们发现在两层 for 循环的暴力枚举过程中&#xff0c;两个指针是可以不回退的&#xff0c;此时我们就可以利用两个指针不回退的性质来优化时间复杂度。因为双指针算法中&#x…

ScratchCard刮刮卡交互元素的实现

效果展示 刮刮卡是⼀种常见的网页交互元素&#xff0c;通过模拟物理世界的刮涂层来揭示下方的内容。这种效果主要依赖于HTML5的 元素来实现。以下是⼀个基于TypeScript的刮刮卡实现示例&#xff0c;包括配置项、初始化方法和核心的刮开逻辑。下面是展示的效果部分刮开效果&…

【Python LeetCode 专题】热题 100,重在思路

哈希1. 两数之和49. 字母异位词分组128. 最长连续序列双指针283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水滑动窗口3. 无重复字符的最长子串438. 找到字符串中所有字母异位词子串560. 和为 K 的子数组239. 滑动窗口最大值普通数组53. 最大子数组和56. 合并区间189. 轮转…

openEuler 22.03 LTS Rootless Docker 安装指南

openEuler 22.03 LTS Rootless Docker 安装指南 1.创建普通用户&#xff08;用于无根模式&#xff09; sudo useradd -m docker-user sudo passwd docker-user # 设置密码 sudo usermod --add-subuids 100000-165535 docker-user sudo usermod --add-subgids 100000-165535 do…

CMake指令:常见内置命令行工具( CMake -E )

目录 1.简介 2.核心作用 3.常用命令介绍 3.1.文件操作命令 3.2.系统命令执行 3.3.校验与哈希 3.4.流程控制与等待 3.5.路径与文件处理 3.6.归档与压缩 3.7.网络与下载 3.8.实用工具 4.使用示例 5.与 shell 命令的对比 6.在 CMake 脚本中使用 7.总结 相关链接 1…

YOLO融合CAF-YOLO中的ACFM模块

YOLOv11v10v8使用教程&#xff1a; YOLOv11入门到入土使用教程 YOLOv11改进汇总贴&#xff1a;YOLOv11及自研模型更新汇总 《CAF-YOLO: A Robust Framework for Multi-Scale Lesion Detection in Biomedical Imagery》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org…

Webpack 项目构建优化详解

1. 相关面试题 1.1. 做过哪些Webpack打包构建优化? 代码分割:使用 Webpack 的 SplitChunksPlugin 进行代码分割,将第三方库、公共代码与业务代码分离,提高缓存利用率和加载速度。 Tree Shaking:通过配置 mode: production 或使用 TerserPlugin,移除未引用的代码,减少…

【深度学习基础】张量与Tensor的区别?从标量到深度学习的多维世界

目录引言一、张量&#xff08;Tensor&#xff09;的定义与特性1. 数学中的张量2. 深度学习中的Tensor二、标量&#xff08;Scalar&#xff09;是什么&#xff1f;三、深度学习中的其他核心量1. 向量&#xff08;Vector&#xff09;2. 矩阵&#xff08;Matrix&#xff09;3. 高阶…

设计模式一: 模板方法模式 (Template Method Pattern)

模板方法模式是一种行为设计模式&#xff0c;它通过定义一个算法的骨架&#xff0c;而将一些步骤延迟到子类中实现。Template Method 使得子类可以不改变&#xff08;复用&#xff09;一个算法结构 即可重定义&#xff08;override 重写&#xff09;该算法的某些特定步骤。基本…

Linux驱动学习day24(UART子系统)

一、UART硬件理论1.1 作用及功能UART&#xff1a;通用异步收发传输器&#xff0c;简称串口。功能&#xff1a;移植u-boot、内核时&#xff0c;主要使用串口查看打印信息。外接各种模块&#xff0c;比如蓝牙GPS模块。使用UART的时候&#xff0c;要注意1. 波特率 2. 格式&#xf…

NFS共享服务器

目录 任务要求 思路总结 1.NFS共享服务 服务端 (ip 192.168.48.128) 客户端 (ip 192.168.48.130) 2.配置autofs自动挂载 任务要求 1.NFS服务器,可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文件系统中,而在本地端的系统中看来&#xff0c;那个远程主机的目…

FreeRTOS学习笔记之队列

小编正在学习嵌入式软件&#xff0c;目前建立了一个交流群&#xff0c;可以留下你的评论&#xff0c;我拉你进群一、简介队列是为了任务与任务、任务与中断之间的通信而准备的&#xff0c;可以在任务与任务、任务与中断之间消息传递&#xff0c;队列中可以存储有限的、大小固定…

垃圾收集器-ZGC

前言在Java开发中&#xff0c;垃圾收集器的选择对系统性能有着致命的影响。Java 8后&#xff0c;虽然G1 GC成为默认&#xff0c;但是它在延迟性控制上仍有限。ZGC作为最新一代高性能低延迟垃圾收集器&#xff0c;解决了CMS和G1在延迟、垃圾堆容量和吞吐量方面的重大突破。本文将…