spring mvc 源码解析之 DispatcherServlet

573 阅读5分钟

DispatcherServlet 是什么

DispatcherServlet 是spring mvc中最最核心的类了,我们可以理解为DispatcherServlet是spring mvc 中大脑,它负责调度工作

image.png

从图中可以看出DispatcherServlet得继承关系大致如下

DispatcherServlet-->FrameworkServlet-->HttpServletBean-->HttpServlet-->GenericServlet
从继承关系可以得知DispatcherServlet本质上还是一个servlet, servlet得生命周期分为三个阶段

  • init()初始化阶段
  • service()处理请求阶段
  • destroy()销毁阶段

接下来我们从每个阶段来解析DispatcherServlet

DispatcherServlet初始化

DispatcherServlet在初始化得时候对spring mvc 九大组件进行了初始化功能

//初始化方法
@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}

/**
 * Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
 //分别调用了spring mvc中九大组件得初始化方法
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);  
   initLocaleResolver(context);    
   initThemeResolver(context);     
   initHandlerMappings(context);  
   initHandlerAdapters(context);   
   initHandlerExceptionResolvers(context);  
   initRequestToViewNameTranslator(context); 
   initViewResolvers(context);
   initFlashMapManager(context);
}

这个时候有的小伙伴就会疑惑,初始化方法不是init()吗,怎么会是onRefresh()方法,其实通过一层层得类继承初始化方法早已不是init(),有兴趣得可以看一下
spring mvc 之 FrameworkServlet 源码解析
HttpServletBean 源码解析

这里只大概梳理一下

  • HttpServletBean 覆盖 GenericServlet 的 init() 方法,该方法调用 initServletBean() 方法,该方法被 FrameworkServlet 覆盖
  • 在 FrameworkServlet 的 initServletBean() 方法中,它调用 initWebApplicationContext() 方法
  • 在该方法中,它检查 webApplicationContext 是否是 ConfigurableWebApplicationContext 的实例
  • 如果是,则调用 configureAndRefreshWebApplicationContext() 方法
  • 因为它在 webApplicationContext 上调用 refresh 方法
  • 查看 AbstractApplicationContext 中 refresh() 方法的实现,最后调用了 finishRefresh() 方法
  • 在该方法中它发布 ContextRefreshedEvent
  • 在 FrameworkServlet 中有实现 ApplicationListener 的私有类 ContextRefreshListener
  • 此类上的 onApplicationEvent() 方法调用 FrameworkServlet 的 onApplicationEvent() 方法
  • 在该方法中,它调用由 DispatcherServlet 覆盖的 onRefresh 方法

DispatcherServlet处理请求

doService是DispatcherServlet处理请求得入口方法,主要流程如下

  • 是否include请求,是得话则进行快照备份,后面在finally会对include中得属性还原
  • 设置一些常见得属性到request中,例如应用上下文,国际化解析器,主题解析器
  • 判断flashMap是否存在,存在得话则进行复原
  • 将请求路径对象化(后面映射匹配的时候用的到)
  • 调用doDispatch处理请求
  • 复原include请求中得属性,还原RequestPath
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   logRequest(request);

   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   // 是否include请求,是得话则进行快照备份,后面在finally会对include中得属性还原
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // Make framework objects available to handlers and view objects.
   //设置一些常见得属性到request中,例如应用上下文,国际化解析器,主题解析器
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   //判断flashMap是否存在,存在得话则进行复原
   if (this.flashMapManager != null) {
      FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
      if (inputFlashMap != null) {
         request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
      }
      request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
      request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
   }

   //将请求路径对象化
   RequestPath previousRequestPath = null;
   if (this.parseRequestPath) {
      previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
      ServletRequestPathUtils.parseAndCache(request);
   }

   //调用doDispatch是真正处理请求得地方
   try {
      doDispatch(request, response);
   }
   //复原include请求中得属性
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         // Restore the original attribute snapshot, in case of an include.
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
      //还原RequestPath
      if (this.parseRequestPath) {
         ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
      }
   }
}
  • 验证当前是否是文件上传请求,是的话重新包装请求
  • 获取Handler处理器,没有获取到则抛出404异常
  • 获取HandlerAdapter处理适配器
  • 判断当请是否是HEAD和GET,判断是否有浏览器缓存,有的话直接返回
  • 执行拦截器得PreHandle方法,如果拦截器返回false直接 return;
  • 执行处理器处理请求,返回ModelAndView对象
  • 当前请求是否异步处理,是的话直接return;
  • 执行拦截器的PostHandle方法
  • 异常处理,渲染页面,执行拦截器的afterCompletion()方法
  • finally块,异步处理调用对应的拦截器,是文件上传请求则删除上传中生成的临时文件
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   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);

         // Determine handler for the current request.
         //获取Handler处理器,没有获取到则抛出404异常
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         
         //获取HandlerAdapter处理适配器
         HandlerAdapter ha = getHandlerAdapter处理适配器(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = HttpMethod.GET.matches(method);
         //HEAD和GET方法,判断是否有浏览器缓存,有的话直接返回
         if (isGet || HttpMethod.HEAD.matches(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }

         //执行拦截器得PreHandle方法,如果拦截器返回false直接 return;
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         
         //执行处理器处理请求,返回ModelAndView对象
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         //当前请求是否异步处理
         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
         
         //检查当前ModelAndView对象是否没有视图名,没有得话则给一个默认的视图名
         applyDefaultViewName(processedRequest, mv);
         
         //执行拦截器的PostHandle方法
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         // As of 4.3, we're processing Errors thrown from handler methods as well,
         // making them available for @ExceptionHandler methods and other scenarios.
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      //异常处理,渲染页面,执行拦截器的afterCompletion()方法
      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 {
         //处理文件上传中的一些临时文件
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

DispatcherServlet得流程大致就如上,销毁阶段这个没有什么东西要说的,其中有很多分支处理是非常重要得,比如ha.handle(processedRequest, response, mappedHandler.getHandler());还有如何获取HandlerMappings,如何获取HandlerAdapter等流程,后面会慢慢去解析