java - 如何确保 @ExceptionHandler(Exception.class) 在 Spring Boot 中最后被调用?

标签 java spring spring-boot exception

我有一个 Controller 处理一些请求:

@RequestMapping(method = RequestMethod.POST, value = "/endpoint")
public ResponseEntity<MyResponse> myEndpoint(@RequestBody MyRequest request) throws Exception {
    //...
}

这样的 Controller 可能会抛出几个异常,为此我使用@ExceptionHandler这样:

@ExceptionHandler(SomeSpecificException.class)
@ResponseBody
public ResponseEntity<Error> handleSomeSpeficicFailure(SomeSpecificException e) {
    //handle specific exception
}

@ExceptionHandler(SomeOtherSpecificException.class)
@ResponseBody
public ResponseEntity<Error> handleSomeOtherSpeficicFailure(SomeOtherSpecificException e) {
    //handle specific exception
}

//etc.

如果引发的异常不属于任何已知类,我添加了一个通用的 Exception.class 处理程序,它返回自定义 500:

@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<Error> handleUnknownFailure(Exception e) {
    //handle unknown exception
}

做了一些测试,看起来效果很好。如果我抛出一个特定的异常,我会在特定的处理程序上调用,如果我抛出一个未映射的异常,我会在通用处理程序上调用。

但是,我没有看到任何提及(无论是在 JavaDoc 还是在 Spring 文档中)关于保证我将首先调用特定方法,然后调用通用方法。

如果 Spring 正在测试特定异常是 instanceof Exception,那么它就是 true,因此它甚至可能首先在这个处理程序上调用我,而不检查其他异常。

我的问题是:

  • 有谁知道添加 @ExceptionHandler(Exception.class) 来处理通用异常是否是一个好习惯?如果不是,正确的做法是什么?
  • 我怎样才能保证类层次结构得到尊重(例如,如果有一天我有 SomeVerySpecificException extends SomeSpecificException,Spring 如何知道它必须在 SomeSpecificException 上调用我 - 直接 parent - 在异常之前 - 祖 parent )?

最佳答案

调试后,我在他们的代码中找到了答案 - 尽管没有记录,但这很遗憾。

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

因此,基本上对于给定的异常,它们首先查找mappedException.isAssignableFrom(exceptionType)的所有映射方法。

创建此列表后,然后:

  • 如果列表为空,则返回 null 并让默认错误处理
  • 如果仅包含一个元素,则返回该元素
  • 如果包含多个元素,它们会按深度(从最近到最远的范围)对它们进行排序,并返回第一个方法。

所以保证不是通过契约(Contract)给出的,而是在实现中,而且看起来确实做得很好。

关于java - 如何确保 @ExceptionHandler(Exception.class) 在 Spring Boot 中最后被调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69673893/

相关文章:

oracle - 在 Spring Data Repository 中刷新 Oracle Materialized View

java - Android(eclipse)图像按钮与背景图像

spring - 为什么 Maven 依赖项的顺序很重要?

java - 垂直合并单元格并将数据插入单元格

java - 从数据库中删除所有消息

java - Jersey Restful : Spring bean creation management

java - Spring boot-将服务注入(inject)doFiler

spring-boot - spring boot 从请求中获取不记名 token 并调用另一个微服务

java - 我有两个水平 ScrollView 。如何一次显示一个并通过单击按钮在它们之间切换?

java - Wicket - 进度/多个标签更新