Spring Boot 全局异常处理策略设计(一):异常不只是 try-catch

@[toc]


Spring Boot 全局异常处理策略设计(一):异常不只是 try-catch

1. 为什么异常值得单独写一整个系列

在多数业务代码中,异常往往被当作一种"不得不写的语法":

php 复制代码
 try {
     service.process();
 } catch (Exception e) {
     log.error("error", e);
 }

但在真实的 Web 系统中,异常从来不是一个语法问题,而是一个系统失控时的兜底机制

一次 HTTP 请求,往往会经历如下链路:

  • Filter
  • Interceptor
  • Controller
  • 参数绑定与校验
  • Service
  • DAO
  • 事务
  • AOP 代理
  • JSON 序列化

异常可以在任何一个环节出现,而且一旦出现,就会"逆着调用栈"向上冒泡,最终由框架决定:

  • 是否回滚事务
  • 是否返回 500
  • 返回什么格式
  • 是否记录堆栈
  • 是否暴露错误信息给前端

因此,异常不是"边角料",而是整个调用链的终点汇合处


2. Java 异常模型的关键认知(只讲对后面有用的)

2.1 Throwable 体系结构

php 复制代码
 Throwable
  ├── Error
  └── Exception
       ├── RuntimeException
       └── Checked Exception
  • Error:JVM 级错误,应用通常无能为力
  • Exception:应用级异常
  • RuntimeException:Spring 默认认为这是"不可恢复异常"
  • Checked Exception:需要显式声明和处理

Spring 事务为什么默认只对 RuntimeException 回滚? 这个问题在后面的事务异常章节会专门展开。


2.2 异常传播是"反向调用链"

正常调用是:

复制代码
 Controller → Service → DAO

异常传播是:

复制代码
 DAO 抛异常 → Service → Controller → 框架

谁最后接住异常,谁就拥有最终解释权。


3. 为什么 Web 系统不能到处 try-catch

3.1 try-catch 的三个常见问题

  1. 吞异常,导致问题被掩盖
  2. 重复代码,Controller 层异常处理泛滥
  3. 破坏事务回滚逻辑

例如:

typescript 复制代码
 @Transactional
 public void createOrder() {
     try {
         saveOrder();
     } catch (Exception e) {
         log.error("error", e);
     }
 }

这个代码看起来稳健,实际上事务已经无法回滚


3.2 异常必须"集中处理"

在 Web 架构中,有一个非常重要的设计原则:

异常应该在"边界层"统一处理,而不是在业务层消化。

Spring MVC 正是基于这个原则,设计了一整套异常处理机制。


4. Spring MVC 的异常处理总体设计思想

4.1 正常流程 vs 异常流程

正常流程:

复制代码
 请求 → Handler → 返回值 → 响应

异常流程:

复制代码
 请求 → Handler → 抛异常 → 异常解析 → 响应

Spring MVC 的核心设计点在于:

异常不是 if-else 分支,而是一条独立的处理链路。


4.2 异常处理在 DispatcherServlet 中的位置

DispatcherServlet 是整个 MVC 的"总控中枢"。

在其核心方法 doDispatch 中,异常被统一捕获:

php 复制代码
 try {
     // 查找 Handler 并执行
 } catch (Exception ex) {
     dispatchException = ex;
 }

这意味着:

  • Controller 不需要感知异常如何返回
  • 框架会统一接管异常

5. Spring MVC 的三种基础异常处理方式

5.1 直接抛出异常(推荐)

typescript 复制代码
@GetMapping("/order")
public Order getOrder() {
    throw new IllegalArgumentException("参数错误");
}

异常会交给框架处理,而不是在 Controller 内部解决。


5.2 @ExceptionHandler:局部异常处理

kotlin 复制代码
@RestController
public class OrderController {

    @ExceptionHandler(IllegalArgumentException.class)
    public String handleIllegalArg(Exception e) {
        return e.getMessage();
    }
}

特点:

  • 只对当前 Controller 生效
  • 适合非常局部的异常场景

5.3 @ControllerAdvice:全局异常处理(重点)

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ErrorResponse handle(Exception e) {
        return new ErrorResponse("500", e.getMessage());
    }
}

这是 Spring Boot 项目中最常见的异常处理入口


6. @ControllerAdvice 的设计价值

6.1 为什么它是"全局异常处理"的核心

@ControllerAdvice 本质上解决了三个问题:

  1. 异常集中管理
  2. 返回格式统一
  3. 与业务逻辑解耦

6.2 多个 ControllerAdvice 的顺序问题

Spring 支持定义多个全局异常处理器:

less 复制代码
@Order(1)
@RestControllerAdvice
class BizExceptionHandler {}

@Order(2)
@RestControllerAdvice
class SystemExceptionHandler {}

优先级越小,越先执行。


7. 异常处理的第一版架构形态

在"入门阶段",一个相对合理的异常架构通常是:

css 复制代码
Controller
   ↓
抛异常
   ↓
@ControllerAdvice
   ↓
统一错误响应

对应的返回结构示例:

css 复制代码
{
  "code": "SYSTEM_ERROR",
  "message": "系统异常,请稍后再试"
}

8. 异常处理流程图(概览)

php 复制代码
throw Exception
HTTP Request
DispatcherServlet
Controller
Exception Resolver
@ExceptionHandler / ControllerAdvice
HTTP Response

图1 Spring MVC 异常处理基本流程图


9. 本篇小结(从入门视角看异常)

到这里,我们只做了三件事:

  1. 纠正"异常只是 try-catch"的认知
  2. 明确异常是 Web 系统的统一出口
  3. 理解 Spring MVC 为什么要集中处理异常

但我们还没有回答几个关键问题:

  • 异常是如何一步步被解析的?
  • 为什么 @ExceptionHandler 能生效?
  • Spring Boot 的 /error 是干什么的?
  • 为什么有些异常进不了 ControllerAdvice?

👉 这些问题,都需要进入源码层面才能解释清楚。


参考资料


结束语

掘金点击访问Qiuner CSDN点击访问Qiuner GitHub点击访问Qiuner Gitee点击访问Qiuner

专栏 简介
📊 一图读懂系列 图文并茂,轻松理解复杂概念
📝 一文读懂系列 深入浅出,全面解析技术要点
🌟持续更新 保持学习,不断进步
🎯 人生经验 经验分享,共同成长

你好,我是Qiuner. 为帮助别人少走弯路而写博客

如果本篇文章帮到了你 不妨点个 吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。

代码都在Github或Gitee上,如有需要可以去上面自行下载。记得给我点星星哦😍

如果你遇到了问题,自己没法解决,可以去我掘金评论区问。CSDN评论区和私信消息看不完 掘金消息少一点.

上一篇推荐 链接
Java程序员快又扎实的学习路线 点击该处自动跳转查看哦
一文读懂 AI 点击该处自动跳转查看哦
一文读懂 服务器 点击该处自动跳转查看哦
2024年创作回顾 点击该处自动跳转查看哦
一文读懂 ESLint配置 点击该处自动跳转查看哦
老鸟如何追求快捷操作电脑 点击该处自动跳转查看哦
未来会写什么文章? 预告链接
一文读懂 XX? 点击该处自动跳转查看哦
2025年终总结 点击该处自动跳转查看哦
一图读懂 XX? 点击该处自动跳转查看哦
相关推荐
Leo July3 小时前
【Java】Spring Security 6.x 全解析:从基础认证到企业级权限架构
java·spring·架构
星火开发设计3 小时前
C++ 数组:一维数组的定义、遍历与常见操作
java·开发语言·数据结构·c++·学习·数组·知识
码道功成3 小时前
Pycham及IntelliJ Idea常用插件
java·ide·intellij-idea
消失的旧时光-19434 小时前
第四篇(实战): 订单表索引设计实战:从慢 SQL 到毫秒级
java·数据库·sql
それども4 小时前
@ModelAttribute vs @RequestBody
java
雨中飘荡的记忆5 小时前
深度详解Spring Context
java·spring
Tao____5 小时前
JAVA开源物联网平台
java·物联网·mqtt·开源·ruoyi
yqd6665 小时前
SpringSecurity的使用
java·spring
仙俊红5 小时前
Java Map 家族核心解析
java·开发语言
一嘴一个橘子6 小时前
springMvc 接收参数、cookie、header
java