SpringMvc-DispatcherServlet原理分析

1.前置知识

  • 本文是针对springMVC请求执行流程来分析,并不会设计到如何使用
  • SpringMVC大体执行流程图,网上很多图,从执行大局看基本上是一致,本文是基于大图分析每一步是如何执行,处理什么来进行分析。

下图来源于网络:

image.png

  • 几个主要的类说明:
    • DispatcherServlet:前端控制器,是SpringMVC全局请求分发器,一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理
    • DispatcherServlet 接收到请求后, 将根据 请求信息 交给 处理器映射器 (HandlerMapping)
    • HandlerMapping 根据用户的url请求 查找匹配该url的 Handler,并返回一个执行链
    • DispatcherServlet 再请求 处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet
    • DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View
    • DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
  • 相关类说明:
    • DispatcherServlet 将页面响应给用户
    • DispatcherServlet:前端控制器
    • HandlerMapping:处理器映射器
    • Handler:处理器
    • HandlAdapter:处理器适配器
    • ViewResolver:视图解析器
    • View:视图

2.源码分析流程图

SpringMvc请求执行.png 上图是后续本文分析源码的流程

3.源码分析

3.1 SpringMVC入口分析

首先请求进来,会先经过一系列过滤器,最后到底FrameworkServlet的service方法,该类是DispatcherServlet的父类,也可以说是先到DispatcherServlet,下面看以下service方法到底会做那些操作:

  1. 判断请求类型是否是null、PATCH,如果是则直接进入processRequest方法,否则调用父类service即httpServlet

FrameworkServlet:

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
   //这里获取请求的类型,判断请求是否是null或者Patch如果是直接进入ProcessRequest方法,否则调用父类的service方法
   HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
   if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
      processRequest(request, response);
   }
   else {
   //调用父类HttpServlet
      super.service(request, response);
   }
}
复制代码

HttpServlet中的service: HttpServlet的service主要操作: 1.判断请求类型,进行调用不同的请求类型的处理方法doGet、doPost等

protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    //获取请求方法
    String method = req.getMethod();
    //判断类型如果是get请求则调doGet
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            doGet(req, resp);
        } else {
            long ifModifiedSince;
            try {
                ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            } catch (IllegalArgumentException iae) {
                ifModifiedSince = -1;
            }
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }
 //判断类型如果是HEAD请求则调doHead
    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
    }
    省略部分....
}
复制代码

具体的doPost、doGet等方法其实在FrameworkServlet中实现的,最终不同的请求类型调用不同方法做完处理之后都会调用processReqest方法 下面简单看FrameworkServlet中doGet和doPost中的实现:

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
//最终调用processRequest方法
   processRequest(request, response);
}

/**
 * Delegate POST requests to {@link #processRequest}.
 * @see #doService
 */
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
//最终调用processRequest方法
   processRequest(request, response);
}
复制代码

3.2 ProcessRequest方法分析

该方法主要三件事:

  1. 初始化web管理器以及注册回调拦截器
  2. 调用doService执行具体逻辑
  3. 通过事件推送吧结果输出
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(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方法
      doService(request, response);
   }
   catch (ServletException | IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }
      logResult(request, response, failureCause, asyncManager);
      //执行完成后进行相关结果处理
      publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}
复制代码

在调用的doService方法核心逻辑: 1.初始化一些可用的处理器以及视图对象 2.调用真正分发的doDispatch方法 下面直接看doDispatch方法: doDispatch方法作用:

1.通过调用getHandler方法获取包含了HandlerMapping的HandlerExecutionChain对象

2.从HandlerExecutionChain对象中通过getHandler获取对应的handlerMethod,然后根据handlerMethod获取handlerAdapter

3.执行HandlerExecutionChain的所有拦截器的前置方法preHandle

4.通过handlerAdapter调用handle去执行具体处理方法,最终是调用到某个controller方法

5.执行handlerExecutionChain中的所有拦截器的后置处理方法applyPostHandle

6.调用processDispatchResult方法处理请求分发结果,主要是处理视图解析等操作

7.最后处理资源清理工作

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   //并不是直接处理的handler,而是handler的执行链,里面会有符合条件的拦截器
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

   try {
      ModelAndView mv = null;
      Exception dispatchException = null;

      try {
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // 这个是核心操作,它主要根据请求url去匹配对应的handlerMapping,然后经过一系列处理获取到handler执行链
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // 此处调用主要是寻找handler的适配器
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }
         //调用handler执行链的所有拦截器的前置处理
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // handler正在执行的方法,即某个controller中的某个方法,然后处理结果返回一个ModelAndView
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
        //执行handler执行链的所有拦截器的后置处理器
         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 {
      if (asyncManager.isConcurrentHandlingStarted()) {
         // Instead of postHandle and afterCompletion
         if (mappedHandler != null) {
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}
复制代码

那么getHandler是如何获取到handler执行链的? 它其实是通过遍历DispatcherServlet中所有的HandlerMapping,然后通过handlerMapping中的getHandler获取handler执行链,但handlerMapping主要分为两种:

  • AbstractUrlHandlerMapping:应对xml中编写的url
  • AbstractHandlerMethodMapping 应对注解形式的controller

而handlerMapping中getHandler方法中主要是进行几个操作:

  • 调用getHandlerInternal方法,该方法是抽象方法,具体实现在对应的handlermapping子类中,主要分为两类:AbstractHandlerMethodMapping这个是基于@RequetMapping等注解形式的handlerMapping,AbstractUrlHandlerMapping类主要是处理可配置的url查找、程序映射到url的等操作比XML里配置一个/hello到对应实现类等可配置url处理。根据reuqest的url调用AbstractUrlHandlerMapping获取handler名称或者对应的handler的Bean名称,这种是基于可配置的url,另外一种是基于方法匹配即controller中定义的每个方法会调用AbstractHandlerMethodMapping
  • 调用getHhandlerInternal后获取到对应handler的bean名称或者实例对象,调用getHandlerExecutionChain构建成HandlerExecutionChain
  • 把获取到的handler放到handlerExecutionChain执行链上
  • 判断是否需要处理跨越问题,如果需要则根据跨域配置以及现有的handler执行链重新构建获取一个新的执行链

然后HandlerMaping中的getHandler方法源码如下:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   //获取handler
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = obtainApplicationContext().getBean(handlerName);
   }
    //根据handler和request获取到具体的handler执行链
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

   if (logger.isTraceEnabled()) {
      logger.trace("Mapped to " + handler);
   }
   else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      logger.debug("Mapped to " + executionChain.getHandler());
   }
//跨域处理
   if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
      CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      config = (config != null ? config.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }

   return executionChain;
}
复制代码

下面分析一些基于注解形式的handler获取: AbstractHandlerMethodMapping的getHandlerInternal方法作用: 1.通过UrlPathHelper工具类根据request获取(url)lookupPath即获取handler的key 2.获取mappingRegistry对象的读锁,避免并发问题还在注册Mapping映射时,出现在获取handler的情况(不知道有没有理解错误) 3.调用lookupHandlerMethod(lookupPath, request);获取handlerMethod对象,该对象包含了方法的参数、返回值、注解等。该方法主要是根据lookupPath即url从MappingRegistry中获取对应的RequetsMappingInfo信息,然后根据映射信息以及url等一些列操作获取到最佳匹配的handlerMethod 4.根据获取到的HandlerMethod对象创建对应的解析器Bean,然后返回 5.解锁

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//通过工具类获取的url这里是lookupPath
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   request.setAttribute(LOOKUP_PATH, lookupPath);
   //获取读锁,避免还早注册,然后这边在读取
   this.mappingRegistry.acquireReadLock();
   try {
   //通过lookupPath湖区哦到对应的handlerMethod,handlerMetho里包含handler
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      //
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
   //然后释放锁
      this.mappingRegistry.releaseReadLock();
   }
}
复制代码

接着看一下getHandlerExecutionChain是如何生成handler执行链的

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
   //遍历所有拦截器
   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
      //通过匹配的区别增加到拦截器的list里保存起来,然后返回
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      }
      else {
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}
复制代码

handler执行链获取到之后,然后进行获取handler的适配器: 遍历所有的handlerAdapters找到对应的adapter,一般是RequestMappingHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   if (this.handlerAdapters != null) {
      for (HandlerAdapter adapter : this.handlerAdapters) {
      //如果支持则直接返回
         if (adapter.supports(handler)) {
            return adapter;
         }
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
复制代码

接着就是执行拦截器的前置处理了,其实就是遍历该handler执行链上的所有拦截器的前置处理方法:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
   //遍历执行
      for (int i = 0; i < interceptors.length; i++) {
         HandlerInterceptor interceptor = interceptors[i];
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}
复制代码

接着是handler执行handle方法做具体逻辑方法调用

AbstractHandlerMethodAdapter:
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
调用子类的方法
   return handleInternal(request, response, (HandlerMethod) handler);
}
复制代码

RequestMappingHandlerAdapter:
1.调用invokeHandlerMethod方法执行处理

2.判断请求头有没有缓存控制,有则进行缓存处理
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // Execute invokeHandlerMethod in synchronized block if required.
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
         //核心处理逻辑方法
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
         //核心处理逻辑方法
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      //核心处理逻辑方法
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
      
         prepareResponse(response);
      }
   }

   return mav;
}
复制代码

下面方法是具体handler执行并且返回ModelAndView,主要做了以下几个操作: 该方法是主要handler处理逻辑: 1.先handlerMethod获取到web数据绑定工厂 2.获取模型工厂 3.根据handlerMethod创建出ServletInvocableHandlerMethod对象,该对象还需要设置一下handlerMethod的参数解析器、返回值处理器、数据绑定工厂、参数名处理对象,是一个具有执行、解析、处理参数一个执行方法对象. 4.servletInvocableHandlerMethod对象调用invokeAndHandle方法执行,最底层是基于反射执行Method来处理的 5.执行完成后通过返回值处理器returnValueHandlers处理返回值,然后调用getModelAndView方法获取到ModelAndView

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
     //获取数据绑定工厂\模型解析以及参数解析器、返回值处理handler等等
   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

      if (asyncManager.hasConcurrentResult()) {
         Object result = asyncManager.getConcurrentResult();
         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
         asyncManager.clearConcurrentResult();
         LogFormatUtils.traceDebug(logger, traceOn -> {
            String formatted = LogFormatUtils.formatValue(result, !traceOn);
            return "Resume with async result [" + formatted + "]";
         });
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }
       //具体执行请求方法,底层基于反射调用具体的业务逻辑方法去处理
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }
       //处理结果并且返回对应的ModelAndView
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}
复制代码

返回对应的ModelAndView之后,接着就是执行对应拦截器的后置处理方法, 最后就是调用processDispatchResult方法处理结果,该方法大致做了以下几点: 该方法主要做两件事:

1.判断前面执行过程中有没有异常,则遍历调用DispatcherServlet中所有的异常解析处理器HandlerExceptionResolver的resolveException(所有的异常解析处理器都必须实现改接口或者实现AbstractHandlerExceptionResolver的抽象子类,平常自定义异常解析可以基于上面者两个类做扩展)

2.没有异常的通过调用render方法处理视图,分两种请情况,前面获得的modeAndViews是否指定了视图名称,如果是则通过视图解析器处理比如:BeanNameViewResolver\FreeMarkerViewResolver、InternalResourceViewResolver等,如果不是则从ModeAndView获取到对应的视图,里面有多种视图包括处理json的MappingJackson2JsonView以及模板引擎的FreeMarkerView,也可以自定义视图处理,可以通过实现AbstractView或者想简单扩展json视图可以通过继承AbstractJackson2View来实现。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable Exception exception) throws Exception {
   boolean errorView = false;
   //异常视图处理
   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()) {
      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) {
      // Exception (if any) is already handled..
      mappedHandler.triggerAfterCompletion(request, response, null);
   }
}
复制代码

由于篇幅有限,其他一些方法可以通过流程图以及具体源码类去了解

猜你喜欢

转载自juejin.im/post/7036038345062875149
今日推荐