首页 > 解决方案 > 为什么Spring在处理端点异常时将RuntimeException包装在NestedServletException中?

问题描述

根据Servlet 规范

servlet 或过滤器在处理请求期间可能会抛出以下异常:

  1. 运行时异常或错误
  2. ServletExceptions 或其子类
  3. IOExceptions 或其子类

如果我们看一下org.springframework.web.servlet.FrameworkServlet#processRequest,我们会看到 Spring 抛出ServletExceptionand IOException,但包装了其他的,包括RuntimeExceptions

try {
    doService(request, response);
} catch (ServletException | IOException ex) {
    failureCause = ex;
    throw ex;
} catch (Throwable ex) {
    failureCause = ex;
    throw new NestedServletException("Request processing failed", ex);
}

为什么 Spring 不处理RuntimeExceptionlike IOException

UPD:换句话说,如果他们以这种方式处理异常会发生什么错误:

try {
    doService(request, response);
} catch (ServletException | IOException | RuntimeException ex) {
    failureCause = ex;
    throw ex;
} catch (Throwable ex) {
    failureCause = ex;
    throw new NestedServletException("Request processing failed", ex);
}

标签: javaspringspring-bootspring-mvc

解决方案


doService这是必需的,因为在内部调用的受保护抽象方法processRequest可以抛出任何已检查或未检查Exception的。

protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;

现在,假设您doService像这样覆盖:

@Override
protected void doService(Long request, Long response) throws ClassNotFoundException {
// whatever ...
}

这将是完全合法的,但随后processRequest可能会引发ClassNotFoundException您必须将其声明为已检查异常的情况。并且因为processRequest由和其他 API 方法使用doGetdoPost这些也必须声明ClassNotFoundException,这违反了规范。

请注意,这主要适用于doService不是由org.springframework.web.servlet.DispatcherServlet. doServiceDispatcherServlet调用中doDispatch并且doDispatch已经捕获了除ServletExceptionor之外的所有内容IOException。但是,仍然需要再次捕获异常,因为 and 的声明doServicedoDispatch没有将它们检查的异常列表限制为ServletExceptionand IOException

21/11/2019 编辑

我认为您的替代异常处理约定没有任何问题。Indeed 更接近于字面解释的规范。该实现只是包装了所有不是 ServletException 或 IOException 的东西。这可能是因为稍后处理程序对异常类型敏感。但至少DispatcherServlet使用的DefaultHandlerExceptionResolver并非如此。

我看不到任何明显的问题,这可能会影响 web.xml 中的错误处理,使用<error-page><exception-type>...</exception-type></error-page>或使用@Componentimplementation ErrorPageRegistrar


推荐阅读