spring mvc 源码解析之 HandlerMapping

817 阅读3分钟

HandlerMapping 是 spring mvc中一个核心类,其主要功能就是为请求找到合适的处理器,我们编写的controller就是处理器,也是当下最流行的处理器

HandlerMapping的初始化

想要了解HandlerMapping的初始化,首先得了解DispatcherServlet是如何初始化得,有兴趣得话可以看一看 spring mvc 源码解析之 DispatcherServlet

DispatcherServlet在初始化得时候,调用了九大组件得初始化方法,其中就有HandlerMapping

@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.
*/
protected void initStrategies(ApplicationContext context) {
  initMultipartResolver(context);
  initLocaleResolver(context);
  initThemeResolver(context);
  initHandlerMappings(context);  //初始化HandlerMappings
  initHandlerAdapters(context);
  initHandlerExceptionResolvers(context);
  initRequestToViewNameTranslator(context);
  initViewResolvers(context);
  initFlashMapManager(context);
}

initHandlerMappings(context)

/**
 * Well-known name for the HandlerMapping object in the bean factory for this namespace.
 * Only used when "detectAllHandlerMappings" is turned off.
 * @see #setDetectAllHandlerMappings
 */
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;
   //detectAllHandlerMappings默认情况下是true,所以大多数情况下是一定会进到这个里面,可以通过set方法设置成false
   if (this.detectAllHandlerMappings) {
      // 查看ApplicationContext容器中所有得HandlerMapping
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      //HandlerMapping不为空得情况,则对其进行排序
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   else {
      //如果detectAllHandlerMappings为false得话,则去查找HANDLER_MAPPING_BEAN_NAME这个常量类型得HandlerMapping
      try {
         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
         this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
         // Ignore, we'll add a default HandlerMapping later.
      }
   }

   // Ensure we have at least one HandlerMapping, by registering
   // a default HandlerMapping if no other mappings are found.
   //如果以上两种方式还是没有查询到HandlerMapping,那么则获取默认得HandlerMapping
   if (this.handlerMappings == null) {
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }

   for (HandlerMapping mapping : this.handlerMappings) {
      if (mapping.usesPathPatterns()) {
         this.parseRequestPath = true;
         break;
      }
   }
}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
   if (defaultStrategies == null) {
      try {
         // Load default strategy implementations from properties file.
         // This is currently strictly internal and not meant to be customized
         // by application developers.
         //
        // 获取到org.springframework.web.servlet包下DispatcherServlet.properties文件中得org.springframework.web.servlet.HandlerMapping属性
         ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
         defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
      }
      catch (IOException ex) {
         throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
      }
   }
    //根据属性值反射创建HandlerMapping
   String key = strategyInterface.getName();
   String value = defaultStrategies.getProperty(key);
   if (value != null) {
      String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
      List<T> strategies = new ArrayList<>(classNames.length);
      for (String className : classNames) {
         try {
            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
            Object strategy = createDefaultStrategy(context, clazz);
            strategies.add((T) strategy);
         }
         catch (ClassNotFoundException ex) {
            throw new BeanInitializationException(
                  "Could not find DispatcherServlet's default strategy class [" + className +
                  "] for interface [" + key + "]", ex);
         }
         catch (LinkageError err) {
            throw new BeanInitializationException(
                  "Unresolvable class definition for DispatcherServlet's default strategy class [" +
                  className + "] for interface [" + key + "]", err);
         }
      }
      return strategies;
   }
   else {
      return Collections.emptyList();
   }
}

流程大致如下:

  • 默认情况下detectAllHandlerMappings是为true得,所有直接去加载ApplicationContext容器得所有HandlerMapping,在不为空得情况下在对HandlerMapping进行排序
  • detectAllHandlerMappings为false得话,仅仅去创建了handlerMapping得bean
  • 在以上两种情况都没有找到handlerMapping,默认会去org.springframework.web.servlet包下DispatcherServlet.properties文件中得获取org.springframework.web.servlet.HandlerMapping属性,通过属性值反射创建HandlerMapping

HandlerMapping初始化之后得到了什么
基于spring mvc 5.3.9,springboot方式下得到的HandlerMapping比这多得多 image.png

目前得到了三个HandlerMapping,其中最重要就是 RequestMappingHandlerMapping,顾名思义就是针对@RequestMapping注解得,也是我们开发中最常见得方式 RequestMappingHandlerMapping主要包含处理器以及拦截器

image.png

image.png

HandlerMapping 处理请求阶段

  • DispatcherServlet在处理请求得时候,会调用HandlerMapping得getHandler()方法得到一个HandlerExecutionChain对象,
  • getHandler()会根据request请求参数得到{GET [/index]}字符串和RequestMappingInfo进行匹配得handle处理器, 遍历所有拦截器,将通用拦截器以及根据Url匹配得拦截器放入集合中,最后将handle处理器和拦截器集合封装成HandlerExecutionChain对象
  • DispatcherServlet处理请求之前会先执行拦截器得preHandler方法,然后通过HandlerAdapter执行处理器对请求进行处理 image.png
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.
         //获取HandlerExecutionChain对象,对象中包含处理器以及拦截器
         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;
            }
         }
         //执行拦截器PreHandle
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         
         //通过处理适配器执行处理器处理请求
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }

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