SpringMVC源码解析——前置控制器DispatcherServlet

点击回顾SpringMVC请求响应流程

前置控制器类

前置控制器DispatcherServlet,间接继承自HttpServlet,本质上还是Servlet

SpringMVC源码解析——前置控制器DispatcherServlet_第1张图片
1565316555822.png

当请求的url符合前置控制器DispatcherServlet的映射路径时,Servlet容器(Tomcat)会调用其service方法,其实现在父类FrameworkServlet中

  1. 查看FrameworkServlet的service方法(看看它怎么处理请求)
@Override
protected void service(...) throws ... {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    //增加对 PATCH 请求的处理
    if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
        processRequest(request, response);
    }
    else {
        super.service(request, response);
    }
}

//重写doGet()方法
@Override
protected final void doGet(...) throws ... {
    processRequest(request, response);
}
//重写doPost()方法
@Override
protected final void doPost(...) throws ... {
    processRequest(request, response);
}

FrameworkServlet的service方法处理了Patch、Get、Post三种类型请求(通过调用processRequest方法)

  1. 查看FrameworkServlet的processRequest方法(进一步看看请求如何被处理)
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
 ​
  long startTime = System.currentTimeMillis();
  Throwable failureCause = null;
 ​
  //获取之前的Locale上下文,同时从request中获取Locale上下文
  //Locale上下文接口用于获取对象Locale(用于构造Java国际化情景),只有一个方法——getLocale()
  LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  LocaleContext localeContext = buildLocaleContext(request);
 ​
  //获取之前的Request属性数据,同时从request中获取新的Request属性数据
  RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
 ​
  WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
 ​
  //初始化上下文
  initContextHolders(request, localeContext, requestAttributes);
 ​
  try {
  //doService() FramworkServlet没有实现,只是简单定义,交由 DispatchServlet实现
  doService(request, response);
  }
  //异常处理,采用捕获,记录然后再抛出给高层的处理策略
  catch (ServletException ex) {
  failureCause = ex;
  throw ex;
  }
  catch (IOException ex) {
  failureCause = ex;
  throw ex;
  }
  catch (Throwable ex) {
  failureCause = ex;
  throw new NestedServletException("Request processing failed", ex);
  }
 ​
  finally {
  //如果失败,恢复上一次请求的上下文 
  ...
  省略
  ...
  }
 }

可以看到FrameworkServlet的processRequest方法的职责是切换上下文(通过request设置上下文,遭遇异常会恢复原上下文),然后调用子类(DispatcherServlet)的doService方法

  1. 查看DispatcherServlet的doService方法(看看请求到底怎么被处理)

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
     ...
    
     //为request设置上下文及其他属性,方便其他方法需要时从request获取
     //...
     request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
     //省略
     //...
    ​
     try {
     //将请求进行分派处理
     doDispatch(request, response);
     }
     finally {
     //...
     //省略
     //...
     }
    }
    

    DispatcherServlet的doService方法给request装填更多数据(),然后调用doDispatch方法最终将请求进行分派处理

  2. 查看DispatcherServlet的doDispatch方法(看请求如何被分派并处理)

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     HttpServletRequest processedRequest = request;
     //定义Handler执行链
     HandlerExecutionChain mappedHandler = null;
     boolean multipartRequestParsed = false;
    ​
     WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    ​
     try {
     //定义ModelAndView
     ModelAndView mv = null;
     Exception dispatchException = null;
    ​
     try {
     //检查请求是否为文件上传请求,如果是使文件上传解析器可用
     processedRequest = checkMultipart(request);
     //如果是文件上传请求multipartRequestParsed值为true
     multipartRequestParsed = (processedRequest != request);
    ​
     //获取请求对应的handler执行链
     //getHandler方法在Handler映射器环节讲解
     mappedHandler = getHandler(processedRequest);
     if (mappedHandler == null || mappedHandler.getHandler() == null) {
     noHandlerFound(processedRequest, response);
     return;
     }
    ​
     // 为Handler执行链中的Handler构建适配器
     // mappedHandler.getHandler()获取的是Handler执行链的Handler——在Handler执行链环节讲解
     HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    ​
     // request的类型
     String method = request.getMethod();
     boolean isGet = "GET".equals(method);
     if (isGet || "HEAD".equals(method)) {
     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
     if (logger.isDebugEnabled()) {
     logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
     }
     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
     return;
     }
     }
    ​
     if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     return;
     }
    ​
     // 适配器执行Handler执行链,返回ModelAndView
     //适配器的handle方法在Handler适配器讲解
     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    ​
     if (asyncManager.isConcurrentHandlingStarted()) {
     return;
     }
    ​
     applyDefaultViewName(processedRequest, mv);
     mappedHandler.applyPostHandle(processedRequest, response, mv);
     }
    
     //捕获异常,只记录(会传递给响应)
     catch (Exception ex) {
     dispatchException = ex;
     }
     catch (Throwable err) {
     dispatchException = new NestedServletException("Handler dispatch failed", err);
     }
    
     //向响应传递结果(包含异常)
     processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
     }
    
     //捕获响应传递过程中的异常
     catch (Exception ex) {
     triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
     }
     catch (Throwable err) {
     triggerAfterCompletion(processedRequest, response, mappedHandler,
     new NestedServletException("Handler processing failed", err));
     }
     finally {
     //...
     //省略
     //...
     }
    }
    

    可以看出doDispatch方法将请求分派给Handler执行链(调用Handler映射器得到Handler执行链、获取并调用Handler适配器执行Handler执行链),之后调用processDispatchResult对结果ModelAndView进行解析并装填响应结果

  3. 查看processDispatchResult方法(看看结果ModelAndView如何被装填进响应中)

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
     @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
     @Nullable Exception exception) throws Exception {
    ​
     boolean errorView = false;
    ​
     //若之前的流程存在异常,使用异常ModelAndView填装参数(此处重构手段是:使用特例对象取代null值)
     if (exception != null) {
     if (exception instanceof ModelAndViewDefiningException) {
     logger.debug("ModelAndViewDefiningException encountered", exception);
     mv = ((ModelAndViewDefiningException) exception).getModelAndView();
     }
     else {
     Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
     mv = processHandlerException(request, response, handler, exception);
     errorView = (mv != null);
     }
     }
    ​
     if (mv != null && !mv.wasCleared()) {
     // 通过ModelAndView渲染视图并填装至response
     render(mv, request, response);
     if (errorView) {
     WebUtils.clearErrorRequestAttributes(request);
     }
     }
     else {
     if (logger.isTraceEnabled()) {
     logger.trace("No view rendering, null ModelAndView returned.");
     }
     }
    ​
     if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
     // Concurrent handling started during a forward
     return;
     }
    ​
     if (mappedHandler != null) {
     mappedHandler.triggerAfterCompletion(request, response, null);
     }
    }
    ​
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
     // 获取请求的Locale对象并装入响应
     Locale locale =
     (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
     response.setLocale(locale);
    ​
     View view;
     String viewName = mv.getViewName();
     if (viewName != null) {
     // ModelAndView指定了视图名称
     // 解析指定名称的视图
     view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
     if (view == null) {
     throw new ServletException(略);
     }
     }
     else {
     // ModelAndView未指定视图名称
     // 从ModelAndView中取出View,此View由Handler(Controller)写入
     view = mv.getView();
     if (view == null) {
     throw new ServletException(略);
     }
     }
    ​
     // Delegate to the View object for rendering.
     if (logger.isTraceEnabled()) {
     logger.trace("Rendering view [" + view + "] ");
     }
     try {
     if (mv.getStatus() != null) {
     response.setStatus(mv.getStatus().value());
     }
     //将View装入响应中
     view.render(mv.getModelInternal(), request, response);
     }
     catch (Exception ex) {
     if (logger.isDebugEnabled()) {
     logger.debug("Error rendering view [" + view + "]", ex);
     }
     throw ex;
     }
    }
    ​
    protected View resolveViewName(String viewName, @Nullable Map model,
     Locale locale, HttpServletRequest request) throws Exception {
    ​
     if (this.viewResolvers != null) {
     //调用视图解析器生成指定名称的View
     for (ViewResolver viewResolver : this.viewResolvers) {
     //视图解析器的resolveViewName方法在视图解析器环节讲解
     View view = viewResolver.resolveViewName(viewName, locale);
     if (view != null) {
     return view;
     }
     }
     }
     return null;
    }
    

    processDispatchResult方法通过调用render方法渲染视图(View)并装填响应结果(异常情况也被封装成ModelAndView进行渲染),render方法则会根据ModelAndView的数据决定是使用指定视图名加载并填充视图(resolveViewName方法)还是直接从ModelAndView取出视图,然后用视图填装结果

你可能感兴趣的:(SpringMVC源码解析——前置控制器DispatcherServlet)