java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot异常处理try-catch

Spring Boot异常处理try-catch应该怎么使用?

作者:Qiuner

这篇文章详细介绍了Web系统中异常处理的重要性,以及SpringMVC的异常处理机制,解释了异常在系统中的角色,讨论了Java异常模型的关键认知,包括Throwable体系结构和异常传播,强调了在Web系统中不应该到处使用try-catch,而是应该在边界层统一处理异常

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

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

try {
    service.process();
} catch (Exception e) {
    log.error("error", e);
}

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

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

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

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

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

2.1 Throwable 体系结构

Throwable
 ├── Error
 └── Exception
      ├── RuntimeException
      └── Checked Exception

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

2.2 异常传播是“反向调用链”

正常调用是:

Controller → Service → DAO

异常传播是:

DAO 抛异常 → Service → Controller → 框架

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

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

3.1 try-catch 的三个常见问题

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

例如:

@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 中,异常被统一捕获:

try {
    // 查找 Handler 并执行
} catch (Exception ex) {
    dispatchException = ex;
}

这意味着:

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

5.1 直接抛出异常(推荐)

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

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

5.2 @ExceptionHandler:局部异常处理

@RestController
public class OrderController {

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

特点:

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

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

@Order(1)
@RestControllerAdvice
class BizExceptionHandler {}

@Order(2)
@RestControllerAdvice
class SystemExceptionHandler {}

优先级越小,越先执行。

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

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

Controller
   ↓
抛异常
   ↓
@ControllerAdvice
   ↓
统一错误响应

对应的返回结构示例:

{
  "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 为什么要集中处理异常

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

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

到此这篇关于Spring Boot异常处理try-catch应该怎么使用?的文章就介绍到这了,更多相关Spring Boot异常处理try-catch内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

参考资料

您可能感兴趣的文章:
阅读全文