spring boot 全局异常处理无法直接捕获资源配额异常,因为这类异常通常由操作系统或容器在进程外部抛出,导致 jvm 进程直接崩溃,而非通过 java 的 try-catch 机制传递。要捕获并处理这种情况,必须使用 runtime.addshutdownhook 注册一个关闭钩子,或者配置操作系统的信号处理器(如 sigterm),在进程终止前执行清理逻辑。

为什么标准 @ExceptionHandler 无效
标准的 Spring MVC 异常处理依赖于请求-响应循环中的异常传播,而资源配额异常(如 OutOfMemoryError、StackOverflowError)属于 Error 类型,它们会中断当前线程甚至整个 JVM,不会进入 DispatcherServlet 的异常处理链。因此,任何试图在 Controller 或 Service 层捕获这些异常的代码都是无效的。

如何正确实现优雅停机与状态记录
为了在资源耗尽时仍能记录日志或通知监控系统,开发者需要在应用启动时注册一个 Shutdown Hook。这个钩子会在 JVM 接收到终止信号(如 SIGKILL 除外)或正常关闭时被调用。在这个钩子中,可以执行关键的清理工作,例如将当前的内存状态写入文件,或者向监控服务发送告警。这种方法确保了即使在极端情况下,也能保留部分诊断信息。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 注册关闭钩子以捕获非正常退出
app.addListeners(new ApplicationListener<applicationfailedevent>() {
@Override
public void onApplicationEvent(ApplicationFailedEvent event) {
System.err.println("Application failed to start or crashed: " + event.getException().getMessage());
// 在此处添加日志记录或告警逻辑
}
});
app.run(args);
}
}</applicationfailedevent>
上述代码展示了如何在 Spring Boot 启动阶段监听失败事件。当 JVM 因资源问题即将终止时,如果是在启动阶段失败,该监听器会被触发。对于运行期间的崩溃,更通用的做法是直接使用 Runtime.getRuntime().addShutdownHook()。需要注意的是,关闭钩子必须在有限的时间内完成执行,否则 JVM 会强制终止进程。











