后面讲过了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进一步解决:

@RestControllerpublic 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初始化过程(续)