请求分发中心:DispatcherServlet

  1. 整体流程

1.1 请求入口

我们知道在Spring MVC中所有的请求入口是在FrameworkServlet的processRequest方法,下面就从该方法开始往下探索:

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);

   //得到当前请求的异步管理器,用于异步响应结果提供支持,Servlet 3.0引入的异步请求的支持
   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   //为异步请求注册一个Callable拦截器,RequestBindingInterceptor这个拦截器只做了一些初始化本地上下文和重置上下文的操作,
   //请求的处理和当前线程是异步的关系,所以在其他线程执行初始化操作时需要执行这个拦截器用户当前请求参数的一些初始化
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
       //初始化上下文持有器,如request,locale,requestattribute,该方法的作用呢主要是给LocaleContextHolder,RequestContextHolder
   //设置值
   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);
   }
}

1.2执行服务方法

下面将带大家进行doService的分析,当请求过来时调用的是DispatcherServlet的doService方法,话不多说,直接看代码。

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.
   //保存请求快照用于请求完成后恢复
   Map<String, Object> attributesSnapshot = null;
   //当请求类型为include,保存当前请求属性的快照,该功能用于在前端jsp中使用了Include标签的jsp页面
   //获取当前请求的上下文信息
   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.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管理器,用于跨请求的参数传递,如我们常使用的RedirectAttribute

//底层使用Session实现参数传递
   if (this.flashMapManager != null) {
      //得到一个当前请求的FlashMap,值为上一次请求输出的FlashMap
      FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
      if (inputFlashMap != null) {
         //如果falshMap不为空,则放入请求属性中,提供给后面的Model使用
         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);
   }

   try {
      //执行核心的分发逻辑
      doDispatch(request, response);
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         // Restore the original attribute snapshot, in case of an include.
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
      if (this.parseRequestPath) {
         ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
      }
   }
}

1.3请求分发处理

当请求进入doDispatcher方法后,会执行所有请求的处理操作,包括请求分发,响应处理等核心操作。在该方法中提现了非常好的封装和分层设计思想。

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 {
         //判断是不是多块请求,如果是多块请求则赋值给processRequest,用于保存该请求
         //请求类型为StandardMultipartHttpServletRequest
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
         //获取可处理当前请求的请求处理器,通过HandlerMapping查找,
         //请求处理器中封装了拦截器链和处理器
         //拦截器链通过与request中的路径进行匹配
         //请求处理器是当应用启动初始化时已经初始化完成,只需要跟据request的请求路径进行查找匹配合适的处理器
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         //根据当前请求的处理器获取支持该处理器的适配器
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

         // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = HttpMethod.GET.matches(method);
         if (isGet || HttpMethod.HEAD.matches(method)) {
            //该目的是用于处理静态资源,如果静态资源没有发生变化,浏览器可直接使用缓存里面的内容
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               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);
      }
      //对上面的结果进行处理,包括异常处理,返回view的则对页面进行渲染,然后执行所有拦截器中的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) {
            //如果是异步请求,则执行拦截器链的afterConcurrentHandlingStarted方法
            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
         }
      }
      else {
         // Clean up any resources used by a multipart request.
         //清理多块请求的资源,我们的多块请求是不需要我们手动清理资源的
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

以上就是对Dispatcher请求分发逻辑处理的主要流程做了一个说明。大家可能对大体的流程已经掌握了,但是每个主流程实现的细节确不是怎么清楚,下面就针对主要的一些流程做一个说明和介绍。

  1. 摘取主要细节介绍

2.1多块请求的处理

在Spring MVC中对多块请求有预处理的操作,就是我们上面看到的判断请求是不是多块请求的那个方法中,下面对该方法进行分析。

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
   //从request的ContentType中判断是不是多块请求
   if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
      if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
         if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
            logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
         }
      }
      else if (hasMultipartException(request)) {
         logger.debug("Multipart resolution previously failed for current request - " +
               "skipping re-resolution for undisturbed error rendering");
      }
      else {
         try {
            //解析多块请求,并返回StandardMultipartHttpServletRequest包装类型
            //主要功能是用于解析request中的上传的文件
            return this.multipartResolver.resolveMultipart(request);
         }
         catch (MultipartException ex) {
            if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
               logger.debug("Multipart resolution failed for error dispatch", ex);
               // Keep processing error dispatch with regular request handle below
            }
            else {
               throw ex;
            }
         }
      }
   }
   // If not returned before: return original request.
   return request;
}

2.2获得处理器

用户的请求都是需要经过处理器的,在Spring MVC中吧请求处理器的查找和执行是分开的,下面来看看是怎么查找请求处理器的。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      //遍历全部映射器
      for (HandlerMapping mapping : this.handlerMappings) {
         //获取本次请求匹配的处理器执行链,包括处理器和拦截器
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

2.3处理器适配器

根据不同的处理器需要对应的适配器去执行,适配器的作用是用于执行处理器,下面来看看获取适配器的方法。

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");
}

2.4 部分组件初始化介绍

我们在上文中经常提到HandlerMapping和HandlerAdapter,那么针对这两个对象是在哪个地方初始化的,又是怎么加载的呢,下面将针对这两个对象的初始化流程做一个分析。

2.4.1 HandlerMapping初始化

在Spring MVC中有RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping这三种类型的HandlerMapping,我们最为熟悉的应当是RequestMappingUrlHandlerMapping,也就是我们经常使用的@RequestMapping注解对应的HandlerMapping。由于其他两种不经常使用所以就针对经常使用的HandlerMapping做一个介绍。

在WebMvcConfigurationSupport中或者WebMvcAutoConfiguration中,如下进行Bean的实例化配置。

public RequestMappingHandlerMapping requestMappingHandlerMapping(
      @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
       //创建RequestMappingHandlerMapping对象
   RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
   //设置初始化顺序
   mapping.setOrder(0);
   //添加拦截器
   mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
   //设置请求中的media-type
   mapping.setContentNegotiationManager(contentNegotiationManager);
   //添加跨域配置
   mapping.setCorsConfigurations(getCorsConfigurations());
       //下面的逻辑都是进行路径匹配规则配置,包括前缀和后缀的一些支持
   PathMatchConfigurer pathConfig = getPathMatchConfigurer();
   if (pathConfig.getPatternParser() != null) {
      mapping.setPatternParser(pathConfig.getPatternParser());
   }
   else {
      mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
      mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());

      Boolean useSuffixPatternMatch = pathConfig.isUseSuffixPatternMatch();
      if (useSuffixPatternMatch != null) {
         mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
      }
      Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
      if (useRegisteredSuffixPatternMatch != null) {
         mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
      }
   }
   Boolean useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
   if (useTrailingSlashMatch != null) {
      mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
   }
   if (pathConfig.getPathPrefixes() != null) {
      mapping.setPathPrefixes(pathConfig.getPathPrefixes());
   }

   return mapping;
}

Bean初始化完成后执行如下方法

public void afterPropertiesSet() {
   this.config = new RequestMappingInfo.BuilderConfiguration();
   是否添加"/"后缀,默认为true
   this.config.setTrailingSlashMatch(useTrailingSlashMatch());
   this.config.setContentNegotiationManager(getContentNegotiationManager());

   if (getPatternParser() != null) {
      this.config.setPatternParser(getPatternParser());
      Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
            "Suffix pattern matching not supported with PathPatternParser.");
   }
   else {
      //是否支持后缀补充,默认为true
      this.config.setSuffixPatternMatch(useSuffixPatternMatch());
      //是否采用mediaType匹配模式,比如.json/.xml模式的匹配,默认为false
      this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
      //默认为AntPathMatcher,路径匹配校验器
      this.config.setPathMatcher(getPathMatcher());
   }

   super.afterPropertiesSet();
}

2.4.2 HandlerAdapterr初始化

在Spring MVC中有SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter、HttpRequestHandlerAdapter等Adapter,下面也只是对RequestMappingHandlerAdapter做一个介绍。

在WebMvcConfigurationSupport中或者WebMvcAutoConfiguration中,如下进行Bean的实例化配置。

public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
      @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcValidator") Validator validator) {
       //创建Adapter
   RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
   //设置Media-type类型的Manager
   adapter.setContentNegotiationManager(contentNegotiationManager);
   //设置消息转换器
   adapter.setMessageConverters(getMessageConverters());
   //绑定Web相关的组件
   adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
   //设置自定义参数解析器
   adapter.setCustomArgumentResolvers(getArgumentResolvers());

//设置自定义返回值处理器
   adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

   if (jackson2Present) {
      adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
      adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
   }

   AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();
   if (configurer.getTaskExecutor() != null) {
      adapter.setTaskExecutor(configurer.getTaskExecutor());
   }
   if (configurer.getTimeout() != null) {
      adapter.setAsyncRequestTimeout(configurer.getTimeout());
   }
   //异步处理请求返回结果
   adapter.setCallableInterceptors(configurer.getCallableInterceptors());
   //主要用于异步处理的拦截器
   adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

   return adapter;
}

初始化RequestMappingHandlerAdapter后执行

public void afterPropertiesSet() {
   // Do this first, it may add ResponseBody advice beans
   //标注了Controlleradvice注解的Controller类的InitBindler和ModelAttribute注解的进行缓存
   initControllerAdviceCache();
       //设置默认的参数解析器
   if (this.argumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
      this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   //有@InitBindler注解的默认参数解析器
   if (this.initBinderArgumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
      this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   //设置默认的返回值处理器
   if (this.returnValueHandlers == null) {
      List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
   }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值