ExceptionHandler的执行顺序

本文探讨了在Spring MVC中使用ExceptionHandler处理异常时的执行顺序问题。当有多个ExceptionHandler处理函数,其中一个捕获的是另一个的父类异常时,源码分析表明,决定执行顺序的关键在于异常匹配度,而非Order属性。通过调试调用栈和深入ExceptionHandlerMethodResolver的getMappedMethod方法,发现系统会选择匹配度最高的ExceptionHandler进行处理。结论是,Exception的继承关系决定了处理顺序,无需额外指定处理顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在项目开发中经常会遇到统一异常处理的问题,在springMVC中有一种解决方式,使用ExceptionHandler。举个例子,

@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler({IllegalArgumentException.class})
    @ResponseBody
    public Result handleIllegalArgumentException(IllegalArgumentException e) {
        logger.error(e.getLocalizedMessage(), e);
        return Result.fail(e.getMessage());
    }

    @ExceptionHandler({RuntimeException.class})
    @ResponseBody
    public Result handleRuntimeException(RuntimeException e) {
        logger.error(e.getLocalizedMessage(), e);
        return Result.failure();
    }
}
复制代码

在这段代码中,我们可以看到存在两个异常处理的函数分别处理IllegalArgumentException和RuntimeException,但是转念一想,就会想到一个问题,IllegalArgumentException是RuntimeException的子类,那么对IllegalArgumentException这个异常又会由谁来处理呢?起初在网上看到一些答案,可以通过Order设置,但是经过简单的测试,发现Order并不起任何作用。虽然心中已有猜测,但还是希望能够找到真正可以证明想法的证据,于是便尝试找到这一块的源码。

源码解读

调用栈

排出掉缓存的情况,主动触发一个IllegalArgumentException异常,经过一步步调试,发现调用栈如下:

核心代码

决定最终选择哪个ExceptionHandler的核心代码为ExceptionHandlerMethodResolver的getMappedMethod方法。代码如下:

private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
  List<Class<? extends Throwable>> matches = new ArrayList<Class<? extends Throwable>>();
  for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
    if (mappedException.isAssignableFrom(exceptionType)) {
      matches.add(mappedException);
    }
  }
  if (!matches.isEmpty()) {
    Collections.sort(matches, new ExceptionDepthComparator(exceptionType));
    return this.mappedMethods.get(matches.get(0));
  }
  else {
    return null;
  }
}
复制代码

这个首先找到可以匹配异常的所有ExceptionHandler,然后对其进行排序,取深度最小的那个(即匹配度最高的那个)。

至于深度比较器的算法如下图,就是做了一个简单的递归,不停地判断父异常是否为目标异常来取得最终的深度。

结论

源码不长,我们也可以很容易地就找到我们想要的答案——ExceptionHandler的处理顺序是由异常匹配度来决定的,且我们也无法通过其他途径指定顺序(其实也没有必要)。

转载于:https://juejin.im/post/5d022d50f265da1bb564f374

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值