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

复制代码
博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。
② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。
③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。
进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。
群公告里还有全网大赛约稿汇总/博客提效工具集/CSDN自动化运营脚本 有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

文章目录

  • [Spring Boot 全局异常处理策略设计(一):异常不只是 try-catch](#Spring Boot 全局异常处理策略设计(一):异常不只是 try-catch)
    • [1. 为什么异常值得单独写一整个系列](#1. 为什么异常值得单独写一整个系列)
    • [2. Java 异常模型的关键认知(只讲对后面有用的)](#2. Java 异常模型的关键认知(只讲对后面有用的))
      • [2.1 Throwable 体系结构](#2.1 Throwable 体系结构)
      • [2.2 异常传播是"反向调用链"](#2.2 异常传播是“反向调用链”)
    • [3. 为什么 Web 系统不能到处 try-catch](#3. 为什么 Web 系统不能到处 try-catch)
      • [3.1 try-catch 的三个常见问题](#3.1 try-catch 的三个常见问题)
      • [3.2 异常必须"集中处理"](#3.2 异常必须“集中处理”)
    • [4. Spring MVC 的异常处理总体设计思想](#4. Spring MVC 的异常处理总体设计思想)
      • [4.1 正常流程 vs 异常流程](#4.1 正常流程 vs 异常流程)
      • [4.2 异常处理在 DispatcherServlet 中的位置](#4.2 异常处理在 DispatcherServlet 中的位置)
    • [5. Spring MVC 的三种基础异常处理方式](#5. Spring MVC 的三种基础异常处理方式)
      • [5.1 直接抛出异常(推荐)](#5.1 直接抛出异常(推荐))
      • [5.2 @ExceptionHandler:局部异常处理](#5.2 @ExceptionHandler:局部异常处理)
      • [5.3 @ControllerAdvice:全局异常处理(重点)](#5.3 @ControllerAdvice:全局异常处理(重点))
    • [6. @ControllerAdvice 的设计价值](#6. @ControllerAdvice 的设计价值)
      • [6.1 为什么它是"全局异常处理"的核心](#6.1 为什么它是“全局异常处理”的核心)
      • [6.2 多个 ControllerAdvice 的顺序问题](#6.2 多个 ControllerAdvice 的顺序问题)
    • [7. 异常处理的第一版架构形态](#7. 异常处理的第一版架构形态)
    • [8. 异常处理流程图(概览)](#8. 异常处理流程图(概览))
    • [9. 本篇小结(从入门视角看异常)](#9. 本篇小结(从入门视角看异常))
    • 参考资料
    • 结束语

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

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

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

java 复制代码
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 体系结构

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

Spring 事务为什么默认只对 RuntimeException 回滚?

这个问题在后面的事务异常章节会专门展开。


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

正常调用是:

text 复制代码
Controller → Service → DAO

异常传播是:

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

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


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

3.1 try-catch 的三个常见问题

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

例如:

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

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


3.2 异常必须"集中处理"

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

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

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


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

4.1 正常流程 vs 异常流程

正常流程:

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

异常流程:

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

Spring MVC 的核心设计点在于:

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


4.2 异常处理在 DispatcherServlet 中的位置

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

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

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

这意味着:

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

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

5.1 直接抛出异常(推荐)

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

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


5.2 @ExceptionHandler:局部异常处理

java 复制代码
@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 支持定义多个全局异常处理器:

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

@Order(2)
@RestControllerAdvice
class SystemExceptionHandler {}

优先级越小,越先执行。


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

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

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

对应的返回结构示例:

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

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

渲染错误: Mermaid 渲染失败: Parse error on line 5: ...Resolver] D --> E[@ExceptionHandler ----------------------^ Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'LINK_ID'

图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? 点击该处自动跳转查看哦
相关推荐
superman超哥2 小时前
Rust 错误处理模式:Result、?运算符与 anyhow 的最佳实践
开发语言·后端·rust·运算符·anyhow·rust 错误处理
强子感冒了2 小时前
Java List学习笔记:ArrayList与LinkedList的实现源码分析
java·笔记·学习
微爱帮监所写信寄信2 小时前
微爱帮监狱寄信写信小程序PHP底层优化框架
java·开发语言·数据库·spring·微信·php·mybatis
MoonPointer-Byte2 小时前
MoonReader:基于 SpringBoot 3.4 & React 的沉浸式协作阅读平台
spring boot·后端·react.js
琥珀.2 小时前
查看linux下java服务进程是否正常
java·linux·运维
猫吻鱼2 小时前
【项目实践09】【基于 Websocket 的同步请求调用】
spring boot·websocket
Coder_Boy_2 小时前
基于SpringAI企业级智能教学考试平台核心模块协同总结与最佳实践方案
java·大数据·人工智能
崎岖Qiu2 小时前
【设计模式笔记23】:长文解析-深刻理解「装饰器模式」
java·笔记·设计模式·装饰器模式
IT_陈寒2 小时前
JavaScript性能优化:7个被低估的V8引擎技巧让你的代码提速50%
前端·人工智能·后端