当前位置: 首页 > news >正文

Spring 全局异常处理机制:多个 @ControllerAdvice 与重复 @ExceptionHandler

Spring 全局异常处理机制:多个 @ControllerAdvice 与重复 @ExceptionHandler

Spring 的异常处理机制允许你通过多个 @ControllerAdvice 类来组织异常处理逻辑。当存在多个处理器处理相同异常时,Spring 会按照特定规则决定使用哪个处理器。

处理规则

  1. 优先级顺序

    • 控制器本地的 @ExceptionHandler 方法优先级最高
    • 然后是按 @ControllerAdvice 类的顺序
    • 最后是默认的 Spring 异常处理
  2. 相同异常处理的选择

    • 当多个 @ControllerAdvice 类中定义了相同的异常处理时,Spring 会选择第一个匹配的处理器
    • 可以通过 @Order 注解或实现 Ordered 接口来控制 @ControllerAdvice 的执行顺序

示例代码

场景描述

假设我们有两个全局异常处理器和一个控制器,都处理 IllegalArgumentException

// 第一个全局异常处理器
@ControllerAdvice
@Order(1)  // 较低优先级
public class GlobalExceptionHandler1 {@ExceptionHandler(IllegalArgumentException.class)public ResponseEntity<String> handleIllegalArgument1(IllegalArgumentException ex) {return ResponseEntity.badRequest().body("Global Handler 1: " + ex.getMessage());}
}// 第二个全局异常处理器
@ControllerAdvice
@Order(0)  // 较高优先级
public class GlobalExceptionHandler2 {@ExceptionHandler(IllegalArgumentException.class)public ResponseEntity<String> handleIllegalArgument2(IllegalArgumentException ex) {return ResponseEntity.badRequest().body("Global Handler 2: " + ex.getMessage());}@ExceptionHandler(NullPointerException.class)public ResponseEntity<String> handleNullPointer(NullPointerException ex) {return ResponseEntity.badRequest().body("NullPointer handled by Handler2");}
}// 控制器类
@RestController
public class MyController {@GetMapping("/test1")public String test1(@RequestParam(required = false) String param) {if (param == null) {throw new IllegalArgumentException("Param is required");}return "Success: " + param;}@GetMapping("/test2")public String test2() {throw new NullPointerException("Oops, null pointer");}// 本地异常处理 - 优先级最高@ExceptionHandler(IllegalArgumentException.class)public ResponseEntity<String> handleLocalIllegalArgument(IllegalArgumentException ex) {return ResponseEntity.badRequest().body("Local Controller Handler: " + ex.getMessage());}
}

测试结果分析

  1. 访问 /test1(抛出 IllegalArgumentException):

    • 首先检查控制器本地的处理器 → 使用本地方法
    • 如果移除本地处理器 → 使用 GlobalHandler2(因为它的 @Order 值更小,优先级更高)
    • 如果 GlobalHandler2 也没有处理 → 使用 GlobalHandler1
  2. 访问 /test2(抛出 NullPointerException):

    • 没有本地处理器 → 使用 GlobalHandler2 中的处理方法
    • 如果 GlobalHandler2 没有处理 → 查找其他 @ControllerAdvice 类中的处理器
    • 如果都没有 → 使用 Spring 默认异常处理

执行顺序总结

  1. 控制器本地@ExceptionHandler 方法(如果有)
  2. 按顺序检查 @ControllerAdvice 类:
    • 先检查 @Order 值较小的类(数值越小优先级越高)
    • 在同一类中按方法声明顺序检查
  3. 最后是 Spring 的默认异常处理

最佳实践建议

  1. 合理组织异常处理器

    • 按业务领域或异常类型分类组织 @ControllerAdvice
    • 例如:ValidationExceptionAdvice, SecurityExceptionAdvice, BusinessExceptionAdvice
  2. 明确指定顺序

    @ControllerAdvice
    @Order(Ordered.HIGHEST_PRECEDENCE)  // 最高优先级
    public class SecurityExceptionAdvice {// 处理安全相关异常
    }@ControllerAdvice
    @Order(Ordered.LOWEST_PRECEDENCE)  // 最低优先级
    public class GenericExceptionAdvice {// 处理通用异常
    }
    
  3. 避免重复处理相同异常

    • 除非有明确需求,否则避免在多个 @ControllerAdvice 中定义相同的异常处理
    • 可以通过继承或组合来复用异常处理逻辑
  4. 记录未处理异常

    @ControllerAdvice
    @Order(Ordered.LOWEST_PRECEDENCE)
    public class LoggingExceptionAdvice {private static final Logger logger = LoggerFactory.getLogger(LoggingExceptionAdvice.class);@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleUncaughtException(Exception ex) {logger.error("Unhandled exception occurred", ex);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("SERVER_ERROR", "An unexpected error occurred"));}
    }
    

通过合理利用多个 @ControllerAdvice 类和 @ExceptionHandler 方法,可以构建出清晰、灵活且易于维护的异常处理体系。

http://www.dtcms.com/a/311914.html

相关文章:

  • CMake 命令行参数完全指南 (1)
  • 数据结构1-概要、单向链表
  • JVM中的垃圾回收暂停是什么,为什么会出现暂停,不同的垃圾回收机制暂停对比
  • 知识随记-----用 Qt 打造优雅的密码输入框:添加右侧眼睛图标切换显示
  • Ubuntu系统间SSH控制详细指南
  • 由浅入深使用LangGraph创建一个Agent工作流
  • 零拷贝技术:高效数据传输的核心原理与应用
  • 用 JavaSwing 开发经典横版射击游戏:从 0 到 1 实现简易 Contra-like 游戏
  • 20250801-2-Kubernetes 存储-节点本地数据卷_笔记
  • IMAP电子邮件归档系统Mail-Archiver
  • UE5 Insight ProfileCPU
  • 自动驾驶嵌入式软件工程师面试题【持续更新】
  • 回归预测 | Matlab实现CNN-LSTM-self-Attention多变量回归预测
  • Java中的字符串 - String 类
  • 编程与数学 03-002 计算机网络 19_网络新技术研究
  • Java试题-选择题(6)
  • 苏州银行招苏新基金研究部研究员
  • python匿名函数lambda
  • Windows Server软件限制策略(SRP)配置
  • linux进度条程序
  • Educational Codeforces Round 181 (Rated for Div. 2) A-C
  • Mujoco(MuJoCo,全称Multi - Joint dynamics with Contact)一种高性能的物理引擎
  • LLM微调笔记
  • 泛型(java!java!java!)
  • 大模型大厂面试题及解析
  • 【MATLAB】(四)函数运算
  • “AI+固态”从蓝海愿景变为刚性需求,消费电池老将转身狂奔
  • MySQL中索引失效的常见场景
  • 人工智能之数学基础:离散型随机事件概率(古典概型)
  • 基于 LightGBM 的二手车价格预测