乐趣区

关于java:Spring-MVC-六-DispatcherServlet处理请求过程

后面讲过了 DispatcherServlet 的初始化过程(源码角度的 DispatcherServlet 的具体初始化过程还没说,先放一放),明天说一下 DispatcherServlet 解决申请的过程。

处理过程

  1. WebApplicationContext 绑定在以后 request 属性上(属性键值 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE)
  2. localResolver 绑定在 request 的属性上(属性键值 LOCALE_RESOLVER_ATTRIBUTE)
  3. themeResolver 绑定在 request 属性上(属性键值 HEME_RESOLVER_ATTRIBUTE)
  4. servlet 容器配置了 multipart resolver,并且以后申请蕴含 multpart file,则包装以后 request 为 MultipartHttpServletRequest。
  5. 匹配以后申请的 handlerMappings,获取到 HandlerExecutionChain,匹配 getHandlerAdapter
  6. 调用 HandlerExecutionChain 的 applyPreHandle 办法:获取拦截器,调用拦截器的 preHandle 办法
  7. 调用 HandlerAdapter 的 handle 办法,这儿会匹配并执行 Conroller 办法
  8. 执行 HandlerExecutionChain 的 applyPostHandle 办法:调用拦截器的 postHandle 办法
  9. 执行 processDispatchResult 办法,其中会调用拦截器的 afterCompletion 办法

以上过程都被 try catch 包围起来了,所以才会有 Spring MVC 的异样解决机制:应用层不论哪里(controller、service、dao 层 …)抛出的异样,都会在这里被捕捉到,注册到 WebApplicationContext 容器中的 HandlerExceptionResolver beans 就有机会对立解决异样。

能够通过 DispatcherServlet 的初始化参数来定制化其行为,参数能够通过 web.xml 指定,包含:

  1. contextClass:指定以后 DispatcherServlet 绑定的容器类(ConfigurableWebApplicationContext 的实现类),默认为 XmlWebApplicationContext。
  2. contextConfigLocation: 上述 contextClass 指定的容器类的配置文件的地位,能够指定多个配置文件,逗号宰割。
  3. namespace:WebApplicationContext 的 namespace,默认[servlet-name]-servlet。
  4. throwExceptionIfNoHandlerFound:某一申请 request 没有匹配到 handle 的话,是否抛出 NoHandlerFoundException 异样,NoHandlerFoundException 随后能够被 HandlerExceptionResolver 捕捉并解决。默认状况下该参数设置为 false,DispatherServlet 不抛出异样、间接导航到 404。留神:如果配置了默认 Servlet Handler(default servlet handling)的话,那么没匹配到的 request 会导航到默认 handler 解决,永远不会呈现 404。

拦挡

HandlerMapping 反对拦截器,拦截器需实现 SpringMVC 的 HandlerInterceptor 接口(org.springframework.web.servlet),蕴含如下办法:

  1. preHandle:HandlerMapping 解决申请之前产生。
  2. postHandle:HandlerMapping 解决申请之后产生。
  3. afterCompletion:整个申请解决实现之后。

preHandle 返回 true 则申请持续被解决,返回 false 则后续不会再解决申请。

postHandle 对 @ResponseBody 和 ResponseEntity 办法简直没有什么作用,因为 response 曾经在 postHandle 之前被 HandlerAdapter 解决实现了,因而不可能被 postHandle 批改了。比方你想通过 postHandle 在 response header 中减少一个头信息是不可能的了。这种需要只能通过 ResponseBodyAdvice、Controller Advice 或者间接在 RequestMappingHandlerAdapter 中间接实现。

异样解决

HandleMapping、HandlerAdapter、Controller 中产生的任何异样,都能够被 DispatcherServlet 捕捉、交给 HandlerExceptionResolver bean 去解决异样。

SpringMVC 提供如下异样解决的实现类:

异样解决链
咱们能够配置多个 HandlerExceptionResolver 作为异样解决链(exception resolver chain)来解决异样,能够通过 order 属性指定其解决程序,order 值越大、在 chain 中排名越靠后。

HandlerExceptionResolver 能够返回:

  1. ModelAndView:谬误页面。
  2. 空 ModelAndView:谬误曾经被解决,不须要导航到谬误页面。
  3. Null:以后 Resolver 不解决,异样持续向上抛给 chain 中前面的 Resolver,直到最初如果没有 Resolver 解决该异样的话,异样会抛出给 Servlet 容器(比方给到 Tomcat,这种状况下 Tomcat 也不解决,可能就会间接抛出给前台)。

SpringMVC 会主动配置内建的异样处理器,咱们能够通过配置客户化异样处理器。SpringMVC 的异样解决绝对比拟重要,前面咱们还会从源码和利用角度做一次剖析。

容器谬误页面

如果异样没有被任何 HandlerExceptionResolver 解决,而且,如果 response status 被设置为 4xx、5xx 的话,servlet 容器(比方 tomcat)会导航到默认的错误处理页面,如果容器配置了错误处理页面的话。能够通过 web.xml 配置:

<error-page>
    <location>/error</location>
</error-page>

以上配置须要 DispatcherServlet 进一步解决:

@RestController
public class ErrorController {@RequestMapping(path = "/error")
    public Map<String, Object> handle(HttpServletRequest request) {Map<String, Object> map = new HashMap<>();
        map.put("status", request.getAttribute("jakarta.servlet.error.status_code"));
        map.put("reason", request.getAttribute("jakarta.servlet.error.message"));
        return map;
    }
}

上一篇 Spring MVC 五 – DispatcherServlet 初始化过程(续)

退出移动版