Spring @Controller异常处理程序和全局异常处理程序。如何调用两者

时间:2017-09-07 04:17:55

标签: java spring spring-mvc spring-boot

我有一个全局异常处理程序可以在REST @Controller之间共享。为此,我使用@ControllerAdvice和一些@ExceptionHandler方法。这很好用。现在,如果我在特定的Rest Controller中添加@ExceptionHandler,那么新的处理程序优先于全局异常处理程序,而全局异常处理程序永远不会被调用。

我需要的是实际上要调用两个。订单无关紧要。关键是有一些全局的,与控制器无关的错误处理代码以及一些特定于控制器的错误处理,我需要两者来执行。这可能吗?例如我可以以某种方式在特定于控制器的处理程序(首先调用)中将异常处理标记为未处理,以便调用行中的下一个处理程序吗?

我知道我可以在@ControllerAdvice中注入@Controller并自己调用特定的全局处理程序,但我宁愿让控制器与全局异常处理程序分离

1 个答案:

答案 0 :(得分:1)

我认为你不能用开箱即用的Spring做到这一点。如果你看一下这个方法ExceptionHandlerExceptionResolver#doResolveHandlerMethodException的内幕,你可以看到Spring首先找到将处理发生的异常的单个方法:

    ...
    ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
    if (exceptionHandlerMethod == null) {
        return null;
    }
    ...

您还可以查看getExceptionHandlerMethod方法的实现。首先,它试图在你的控制器方法中找到适当的处理程序,如果没有找到 - 那么在控制器顾问中。

之后它会调用它:

    try {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
        }
        exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
    }
    catch (Exception invocationEx) {
        if (logger.isErrorEnabled()) {
            logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
        }
        return null;
    }

你还应该注意Spring吞下了原始异常处理过程中可能发生的任何异常,因此你甚至无法从第一个处理程序中抛出新的异常或重新抛出原始异常,因此可以在其他地方捕获它(实际上你可以,但是这是毫无意义的。)

所以,如果你真的想这样做 - 我想唯一的方法是自己编写ExceptionHandlerExceptionResolver(可能是扩展弹簧ExceptionHandlerExceptionResolver)并修改doResolveHandlerMethodException方法,所以看起来乘以exceptionHandlerMethod(一个在控制器内,一个在顾问中)并在链中调用它。这可能很棘手:))

另外,您可以查看this Jira票证。

希望它有所帮助。