在构建现代 Web 系统时,异常处理往往被视为一个简单的语法问题——只需在代码中插入 try-catch 块即可。然而,对于使用 Spring Boot 的开发者来说,这种做法不仅低效,还可能带来严重的架构问题。本文将深入探讨为什么异常需要集中管理,以及 Spring MVC 如何提供优雅的全局处理方案。
1. 异常:系统失控时的兜底机制
许多开发者习惯于在业务代码中到处使用 try-catch,将其视为一种“不得不写的语法”。但在真实的 Web 系统中,异常从来不是一个语法问题,而是系统失控时的兜底机制。一次 HTTP 请求,往往会经历如下链路:
- Filter → Interceptor → Controller
- 参数绑定与校验 → Service → DAO
- 事务 → AOP 代理 → JSON 序列化
异常可以在任何一个环节出现,而且一旦出现,就会“逆着调用栈”向上冒泡。最终由框架决定:是否回滚事务、是否返回 500、返回什么格式、是否记录堆栈、是否暴露错误信息给前端。因此,异常不是“边角料”,而是整个调用链的终点汇合处。
博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。
② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。
③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。
进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。
群公告里还有全网大赛约稿汇总/博客提效工具集/CSDN自动化运营脚本 有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。
2. Java 异常模型的关键认知
要理解 Spring Boot 的异常处理,首先需要掌握 Java 异常模型的核心概念。虽然许多开发者熟悉 try-catch 语法,但往往忽略了异常传播的本质。
try {
service.process();
} catch (Exception e) {
log.error("error", e);
}
2.1 Throwable 体系结构
Java 的异常体系基于 Throwable 类,主要分为两大类:
- Error:JVM 级错误,如 OutOfMemoryError,应用通常无能为力
- Exception:应用级异常,细分为 RuntimeException(不可恢复)和 Checked Exception(需显式处理)
Throwable
├── Error
└── Exception
├── RuntimeException
└── Checked Exception
Spring 事务为什么默认只对 RuntimeException 回滚?
这个问题在后面的事务异常章节会专门展开。
2.2 异常传播是“反向调用链”
正常调用是:Controller → Service → DAO。而异常传播是反向的:DAO → Service → Controller。谁最后接住异常,谁就拥有最终解释权。这个特性决定了全局异常处理的必要性。
Controller → Service → DAO
DAO 抛异常 → Service → Controller → 框架
3. 为什么 Web 系统不能到处 try-catch
在 Web 系统中,滥用 try-catch 会导致三个常见问题:
- 吞异常:捕获后不处理,问题被掩盖
- 重复代码:每个 Controller 都要重复编写异常处理逻辑
- 破坏事务回滚:不当的捕获可能导致事务无法正确回滚
@Transactional
public void createOrder() {
try {
saveOrder();
} catch (Exception e) {
log.error("error", e);
}
}
这个代码看起来稳健,实际上事务已经无法回滚。
因此,异常必须集中处理。在 Web 架构中,有一个非常重要的设计原则:Controller 层不应该关心异常如何返回。这一点与 TypeScript、JavaScript、Python、Go 等语言的最佳实践一致——将错误处理与业务逻辑分离。
异常应该在“边界层”统一处理,而不是在业务层消化。
4. Spring MVC 的异常处理总体设计思想
Spring MVC 基于“集中处理”原则,设计了一整套异常处理机制。其核心思想是:正常流程和异常流程分离。
请求 → Handler → 返回值 → 响应
请求 → Handler → 抛异常 → 异常解析 → 响应
异常不是 if-else 分支,而是一条独立的处理链路。
4.1 DispatcherServlet 的角色
DispatcherServlet 是整个 MVC 的“总控中枢”。在其核心方法 doDispatch 中,异常被统一捕获:
try {
// 查找 Handler 并执行
} catch (Exception ex) {
dispatchException = ex;
}
这意味着 Controller 不需要感知异常如何返回,框架会统一接管异常。这种设计类似于 Java 中异常传播的“反向调用链”特性,但将最终处理权交给了框架。
5. Spring MVC 的三种基础异常处理方式
Spring MVC 提供了三种异常处理方式,从简单到复杂,适用于不同场景。
5.1 直接抛出异常(推荐)
最简洁的方式是直接抛出异常,让框架处理:
@GetMapping("/order")
public Order getOrder() {
throw new IllegalArgumentException("参数错误");
}
5.2 @ExceptionHandler:局部异常处理
适用于非常局部的异常场景,只对当前 Controller 生效:
@RestController
public class OrderController {
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArg(Exception e) {
return e.getMessage();
}
}
5.3 @ControllerAdvice:全局异常处理(重点)
这是 Spring Boot 项目中最常见的异常处理入口:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ErrorResponse handle(Exception e) {
return new ErrorResponse("500", e.getMessage());
}
}
6. @ControllerAdvice 的设计价值
@ControllerAdvice 本质上解决了三个问题:
- 异常集中管理:所有异常在一个地方处理
- 返回格式统一:确保所有错误响应格式一致
- 与业务逻辑解耦:Controller 层无需关心异常处理细节
提示:Spring 支持定义多个全局异常处理器,通过 @Order 注解控制优先级:
@Order(1)
@RestControllerAdvice
class BizExceptionHandler {}
@Order(2)
@RestControllerAdvice
class SystemExceptionHandler {}
优先级越小,越先执行。这在处理不同类型的异常时非常有用,例如先处理业务异常,再处理通用异常。
[AFFILIATE_SLOT_1]7. 异常处理的第一版架构形态
在入门阶段,一个相对合理的异常架构通常包含:
- 统一的返回结构(如 ApiResponse)
- 自定义业务异常类
- 全局异常处理器捕获所有异常
Controller
↓
抛异常
↓
@ControllerAdvice
↓
统一错误响应
对应的返回结构示例:
{
"code": "SYSTEM_ERROR",
"message": "系统异常,请稍后再试"
}

8. 异常处理流程图(概览)
下图展示了 Spring MVC 异常处理的基本流程:

图1 Spring MVC 异常处理基本流程图
9. 本篇小结
到这里,我们只做了三件事:
- 纠正“异常只是 try-catch”的认知
- 明确异常是 Web 系统的统一出口
- 理解 Spring MVC 为什么要集中处理异常
但我们还没有回答几个关键问题:
- 异常是如何一步步被解析的?
- 为什么 @ExceptionHandler 能生效?
- Spring Boot 的 /error 是干什么的?
- 为什么有些异常进不了 ControllerAdvice?
这些问题,都需要进入源码层面才能解释清楚。在后续文章中,我们将深入 DispatcherServlet 源码,揭开异常处理的神秘面纱。
[AFFILIATE_SLOT_2]

| 专栏 | 简介 |
|---|---|
| 一图读懂系列 | 图文并茂,轻松理解复杂概念 |
| 一文读懂系列 | 深入浅出,全面解析技术要点 |
| 持续更新 | 保持学习,不断进步 |
| 人生经验 | 经验分享,共同成长 |
你好,我是Qiuner. 为帮助别人少走弯路而写博客
如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 。
代码都在Github或Gitee上,如有需要可以去上面自行下载。记得给我点星星哦
如果你遇到了问题,自己没法解决,可以去我掘金评论区问。CSDN评论区和私信消息看不完 掘金消息少一点.
| 上一篇推荐 | 链接 |
|---|---|
| Java程序员快又扎实的学习路线 | 点击该处自动跳转查看哦 |
| 一文读懂 AI | 点击该处自动跳转查看哦 |
| 一文读懂 服务器 | 点击该处自动跳转查看哦 |
| 2024年创作回顾 | 点击该处自动跳转查看哦 |
| 一文读懂 ESLint配置 | 点击该处自动跳转查看哦 |
| 老鸟如何追求快捷操作电脑 | 点击该处自动跳转查看哦 |
| 未来会写什么文章? | 预告链接 |
|---|---|
| 一文读懂 XX? | 点击该处自动跳转查看哦 |
| 2025年终总结 | 点击该处自动跳转查看哦 |
| 一图读懂 XX? | 点击该处自动跳转查看哦 |
浙公网安备 33010602011771号