Spring Boot 中多个 @ControllerAdvice 类的加载顺序由 @Order 注解决定,数值越小优先级越高;高优先级类应处理具体异常类型,低优先级类仅兜底处理 Exception.class,避免重复或重叠声明。

Spring Boot 中多个 @ControllerAdvice 类的加载顺序,直接决定异常由谁处理——先匹配到的生效,后续不再执行。关键不是“谁先定义”,而是 Spring 容器注册时的**执行优先级顺序**。
用 @Order 显式指定优先级
这是最常用、最可靠的方式。给每个全局异常处理类加上 @Order 注解,数值越小,优先级越高,越早被检查:
-
@Order(Ordered.HIGHEST_PRECEDENCE)→ 最高优先(如模块 A 的业务异常处理器) -
@Order(Ordered.HIGHEST_PRECEDENCE + 10)→ 次高(如通用参数校验处理器) -
@Order(Ordered.LOWEST_PRECEDENCE)→ 最低(如兜底的Exception.class处理器)
注意:@Order 必须加在类上(不是方法),且仅对 @ControllerAdvice、@RestControllerAdvice、拦截器等支持排序的组件有效。
避免父类异常被提前捕获
异常匹配是按继承关系逐级向上查找的。如果低优先级类中写了 @ExceptionHandler(Exception.class),而高优先级类没覆盖具体子类(如 BusinessException),那么子类异常也会被父类处理器“吃掉”。
建议做法:
- 高优先级类专注处理明确的业务异常、校验异常等具体类型
- 低优先级类只保留一个
@ExceptionHandler(Exception.class)作为兜底 - 不要在多个类里都写同级或重叠的异常类型(例如两个类都处理
RuntimeException)
模块间依赖带来的隐式顺序
在多模块项目中(如 common 模块提供基础异常处理器,A 模块引入并扩展),实际加载顺序受 spring.factories 或自动配置类的 @AutoConfigureBefore/@AutoConfigureAfter 影响。
若发现 common 模块的处理器总是“抢跑”,可:
- 在 A 模块的
@RestControllerAdvice类上加@Order(Ordered.HIGHEST_PRECEDENCE) - 确保 A 模块的配置类在
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中排在 common 之后(Spring Boot 3.2+) - 避免在 common 模块中使用
@Primary声明异常处理器 Bean(不推荐,语义不清且不可靠)
验证是否生效的小技巧
启动应用后,查看日志中类似这样的输出:
Mapped exception handler method [public com.example.Result handleBusinessException(...)] to [class com.example.BusinessException]多观察几行,看不同异常类型是否绑定到了你预期的处理器类上。也可以临时在各处理器方法里加 log.info("I'm handling: {}", e.getClass().getSimpleName()); 辅助判断。











