整体流程图

* 遍历List<HandlerMapping> handlerMappings,调用每一个HandlerMapping的getHandler(request)以获取请求对应的HandlerExecutionChain对象

* 返回第一个匹配HandlerMapping的getHandler(request)的结果

HandlerExecutionChain mappedHandler = this.getHandler(processedRequest);

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Iterator var2 = this.handlerMappings.iterator();
    HandlerExecutionChain handler;
    do {
        if (!var2.hasNext()) {
            return null;
        }
        HandlerMapping hm = (HandlerMapping)var2.next();
        handler = hm.getHandler(request);
    } while(handler == null);

    return handler;
}

在initHandlerMappings里初始化HandlerMapping实例集合

* 在容器中获取HandlerMapping类型的对象,多个就进行排序(可基于@Order),不存在就是要默认配置文件指定的类型

* 在WebMvcConfigurationSupport配置支持类中,默认本类注册以下处理器映射:

  - RequestMappingHandlerMapping(@RequestMapping注解处理器映射) ,顺序为0,用于映射带注解的控制器方法

  - HandlerMapping (处理器映射),顺序1,用于映射url路径和视图名称,基于ViewController方法

  - BeanNameUrlHandlerMapping(bean名称处理器映射),顺序2,用于映射url路径到控制器bean名称

  - RouterFunctionMapping(路由器功能映射),顺序3,用于映射路由函数

  - HandlerMapping (处理器映射),顺序Integer.MAX_VALUE-1,用于处理静态资源请求,基于addResourceHandlers方法

  - HandlerMapping (处理器映射),顺序Integer.MAX_VALUE,用于服务器内部重定向到一个默认的servlet

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    if (this.detectAllHandlerMappings) {
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList(matchingBeans.values());
            OrderComparator.sort(this.handlerMappings);
        }
    } else {
        try {
            HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException var3) {}
    }

    if (this.handlerMappings == null) {
        this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
    }

}

HandlerMapping体系

HandlerMapping接口
HandlerExecutionChain.getHandler(HttpServletRequest)

* 核心方法HandlerExecutionChain getHandler(HttpServletRequest request)

  根据HttpServletRequest信息匹配出一个HandlerExecutionChain实例

public interface HandlerMapping {


   String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
   String LOOKUP_PATH = HandlerMapping.class.getName() + ".lookupPath";
   String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
   String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
   String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
   String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
   String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
   String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";

   @Nullable
   HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

HandlerExecutionChain对象

* 封装了一个HttpServletRequest 最终匹配的信息,包括:

  - 处理器handler,一个用户处理最终请求的处理对象,处理请求的核心逻辑

  - 此请求匹配的拦截器

* 提供了拦截器前置、后置处理的调用方法

  - applyPreHandle前置处理

   ①获取拦截器集合,遍历执行每一个拦截器的preHandle方法

   ②如果一个拦截器的preHandle方法返回false,执行triggerAfterCompletion后返回false,不会执行下一个

   ③triggerAfterCompletion的逻辑是遍历调用每一个拦截器的afterCompletion方法

  - applyPostHandle后置处理

①获取拦截器集合,遍历执行每一个拦截器的postHandle方法,都会执行

* 提供一个afterConcurrentHandlerStarted方法在,整个请求结束之后,即DispatcherServlet的doDispatch的finally里

  用于执行AsyncHandlerInterceptor类型拦截器的afterConcurrentHandlingStarted方法

   

  
public class HandlerExecutionChain {


   private final Object handler;
   @Nullable
   private HandlerInterceptor[] interceptors;
   @Nullable
   private List<HandlerInterceptor> interceptorList;

   private int interceptorIndex = -1;

   public HandlerExecutionChain(Object handler) {
      this(handler, (HandlerInterceptor[]) null);
   }
   public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
      if (handler instanceof HandlerExecutionChain) {
         HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
         this.handler = originalChain.getHandler();
         this.interceptorList = new ArrayList<>();
         CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
         CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
      }
      else {
         this.handler = handler;
         this.interceptors = interceptors;
      }
   }


   public void addInterceptor(HandlerInterceptor interceptor) {
      initInterceptorList().add(interceptor);
   }

   private List<HandlerInterceptor> initInterceptorList() {
      if (this.interceptorList == null) {
         this.interceptorList = new ArrayList<>();
         if (this.interceptors != null) {
            CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
         }
      }
      this.interceptors = null;
      return this.interceptorList;
   }
   @Nullable
   public HandlerInterceptor[] getInterceptors() {
      if (this.interceptors == null && this.interceptorList != null) {
         this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
      }
      return this.interceptors;
   }


   /**
    * Apply preHandle methods of registered interceptors.
    * @return {@code true} if the execution chain should proceed with the
    * next interceptor or the handler itself. Else, DispatcherServlet assumes
    * that this interceptor has already dealt with the response itself.
    */
   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;
   }

   void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
         throws Exception {

      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
         }
      }
   }

   void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
         throws Exception {

      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
               interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
            }
         }
      }
   }


   void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = interceptors.length - 1; i >= 0; i--) {
            if (interceptors[i] instanceof AsyncHandlerInterceptor) {
               try {
                  AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
                  asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
               }
               catch (Throwable ex) {
               }
            }
         }
      }
   }

}

AbstractHandlerMapping

继承WebApplicationObjectSupport

* ApplicationObjectSupport抽象类实现了ApplicationContextAware接口(父Aware接口)

- 封装了applicationContext

- 在Aware实现方法setApplicationContext里:

  ①获取容器传递进来的applicationContext

②调用了一个initApplicationContext(context)方法,子类可以重写对传递进来的ApplicationContext进行自定义处理

* WebApplicationObjectSupport,继承ApplicationObjectSupport,且实现ServletContextAware接口

- 重写了父类的initApplicationContext(context)抽象方法,

①执行super.initApplicationContext(context),其里面又会执行initApplicationContext()

赋值了成员this.servletContext = ((WebApplicationContext) context).getServletContext(),是通过父类的WebApplicationContext中获取到servletContext

②也执行initServletContext(ServletContext servletContext)方法,子类可以重写对传递进来的servletContext进行自定义处理

  - 实现ServletContextAware,在setServletContext(ServletContext servletContext)获取了新servletContext,如果和成员this.servletConte的值不一样就执行initServletContext(ServletContext servletContext) 抽象方法

public abstract class ApplicationObjectSupport implements ApplicationContextAware {

   @Nullable
   private ApplicationContext applicationContext;
   @Nullable
   private MessageSourceAccessor messageSourceAccessor;


   @Override
   public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
      if (context == null && !isContextRequired()) {
         this.applicationContext = null;
         this.messageSourceAccessor = null;
      }
      else if (this.applicationContext == null) {
         if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException();
         }
         this.applicationContext = context;
         this.messageSourceAccessor = new MessageSourceAccessor(context);
         initApplicationContext(context);
      }
      else {
         if (this.applicationContext != context) {
            throw new ApplicationContextException();
         }
      }
   }

   protected void initApplicationContext(ApplicationContext context) throws BeansException {
      initApplicationContext();
   }

   protected void initApplicationContext() throws BeansException {
   }

   ...

}

public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport implements ServletContextAware {

   @Nullable
   private ServletContext servletContext;

   @Override
   public final void setServletContext(ServletContext servletContext) {
      if (servletContext != this.servletContext) {
         this.servletContext = servletContext;
         initServletContext(servletContext);
      }
   }

   @Override
   protected void initApplicationContext(ApplicationContext context) {
      super.initApplicationContext(context);
      if (this.servletContext == null && context instanceof WebApplicationContext) {
         this.servletContext = ((WebApplicationContext) context).getServletContext();
         if (this.servletContext != null) {
            initServletContext(this.servletContext);
         }
      }
   }

   protected void initServletContext(ServletContext servletContext) {
   }

...

}

收集HandlerInterceptor
概述

//保存用户添加进来的的拦截器
private final List<Object> interceptors = new ArrayList<>();

//interceptors进行类型过滤后的最终拦截器集合
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

* 类继承WebApplicationObjectSupport实现了initApplicationContext()方法,执行时间在setApplicationContext方法中,以初始化所有拦截器集合

- 执行抽象方法extendInterceptors(this.interceptors) 子类可能会新增一些Interceptors到此List<Object>interceptors中

- 从容器中查找MappedInterceptor类型的实例集合加入到List<HandlerInterceptor> this.adaptedInterceptors

  MappedInterceptor是HandlerInterceptor接口实现类,可以指定includePatterns、excludePatterns匹配

- 遍历interceptors(用户通过WebMvcConfigurationSupport配置进来)中的拦截器类型,收集到List<HandlerInterceptor> adaptedInterceptors中

如果是HandlerInterceptor类型直接加入adaptedInterceptors,用户自定义的拦截器一般都是此类型,注MappedInterceptor是HandlerInterceptor类型

如果是WebRequestInterceptor需要转为WebRequestHandlerInterceptorAdapter加入adaptedInterceptors

其他类型报错

* 内部也关联了两个辅助组件

  - UrlPathHelper类

是Spring中的一个帮助类,有很多与URL路径有关的实用方法,除了对URL进行去除分号、解码外,还能基于HttpServletRequest获取getContextPath/getServletPath等方法

在本类中使用其getLookupPathForRequest方法返回请求的查找路径,一般返回的是应用中的路径除去ServletPath

  - PathMatcher类

    用于路径上的模式匹配

自定义拦截器流程

* 用户通过实现WebMvcConfigurer接口,调用addInterceptors,使用registry的addInterceptor自定义的拦截器

  - 此方法addInterceptors(InterceptorRegistry registry)会被在getInterceptors(..)中会跳跃用于收集用户自定义的拦截器

  - 用户使用registry.addInterceptor(new xxx())会返回InterceptorRegistration代表一个拦截器注册对象

    如果用户接着添加了.addPathPatterns/excludePathPatterns,那么在执行registry.getInterceptors()的时候会把这个拦截器转为MappedInterceptor

* 每一个HandlerMapping的bean方法中,都会调用getInterceptors(..)取获取拦截器集合

* getInterceptors(..)会把InterceptorRegistry 内部的List<InterceptorRegistration> registrations 返回

  最终会设置到RequestMappingHandlerMappingsetInterceptors(getInterceptors());即AbstractHandlerMapping的List<Object>interceptors中

@Override
public void addInterceptors(InterceptorRegistry registry) {
    super.addInterceptors(registry);
    registry.addInterceptor(new TestInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/emp/toLogin","/emp/login","/js/**","/css/**","/images/**");
}

 
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
      @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
   RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
   mapping.setOrder(0);
   mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));

...

}


protected final Object[] getInterceptors(
      FormattingConversionService mvcConversionService,
      ResourceUrlProvider mvcResourceUrlProvider) {
   if (this.interceptors == null) {
      InterceptorRegistry registry = new InterceptorRegistry();
      addInterceptors(registry);
      registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
      registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
      this.interceptors = registry.getInterceptors();
   }
   return this.interceptors.toArray();
}


protected List<Object> getInterceptors() {
   return this.registrations.stream()
         .sorted(INTERCEPTOR_ORDER_COMPARATOR)
         .map(InterceptorRegistration::getInterceptor)
         .collect(Collectors.toList());
}


//InterceptorRegistration
protected Object getInterceptor() {
    if (this.includePatterns.isEmpty() && this.excludePatterns.isEmpty()) {
        return this.interceptor;
    }

    String[] include = StringUtils.toStringArray(this.includePatterns);
    String[] exclude = StringUtils.toStringArray(this.excludePatterns);
    MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
    if (this.pathMatcher != null) {
        mappedInterceptor.setPathMatcher(this.pathMatcher);
    }
    return mappedInterceptor;
}

实现getHandler(request)方法整体框架

* 实现了HandlerMapping接口的HandlerExecutionChain getHandler(HttpServletRequest request)方法,提供一个模板过程返回HandlerExecutionChain,

  ①向子类暴露一个抽象方法getHandlerInternal以获取对应的处理器handler,表示一个将会处理当前request的方法实体处理器

- 如果为空使用defaultHandler属性指定的

- 具体什么类型有子类决定,例如对应的controller类的一个方法包装类,或者是一个其他类型的对象

  ②如果第①步返回的是String,则会从容器中获取

③执行getHandlerExecutionChain方法获取HandlerExecutionChain,封装了处理器handle和合适的拦截器集合

  - 遍历List<HandlerInterceptor> adaptedInterceptors中的拦截器,如果拦截器是MappedInterceptor,使用mappedInterceptor.matches进行匹配后加入HandlerExecutionChain

  - 否则直接加入HandlerExecutionChain

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
        implements HandlerMapping, Ordered, BeanNameAware {

    @Nullable
    private Object defaultHandler;
    private UrlPathHelper urlPathHelper = new UrlPathHelper();
    private PathMatcher pathMatcher = new AntPathMatcher();

//保存用户添加进来的的拦截器
    private final List<Object> interceptors = new ArrayList<>();

//interceptors进行类型过滤后的最终拦截器集合
    private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

    @Nullable
    private CorsConfigurationSource corsConfigurationSource;
    private CorsProcessor corsProcessor = new DefaultCorsProcessor();
    private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered
    @Nullable
    private String beanName;


    //set/getter

    @Override
    protected void initApplicationContext() throws BeansException {
        extendInterceptors(this.interceptors);
        detectMappedInterceptors(this.adaptedInterceptors);
        initInterceptors();
    }
    
    protected void extendInterceptors(List<Object> interceptors) {
    }
    protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
        mappedInterceptors.addAll(
                BeanFactoryUtils.beansOfTypeIncludingAncestors(
                        obtainApplicationContext(), MappedInterceptor.class, true, false).values());
    }
    protected void initInterceptors() {
        if (!this.interceptors.isEmpty()) {
            for (int i = 0; i < this.interceptors.size(); i++) {
                Object interceptor = this.interceptors.get(i);
                if (interceptor == null) {
                    throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
                }
                this.adaptedInterceptors.add(adaptInterceptor(interceptor));
            }
        }
    }
    protected HandlerInterceptor adaptInterceptor(Object interceptor) {
        if (interceptor instanceof HandlerInterceptor) {
            return (HandlerInterceptor) interceptor;
        }
        else if (interceptor instanceof WebRequestInterceptor) {
            return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
        }
        else {
            throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
        }
    }

    
    @Override
    @Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        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);
        }

        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

        if (hasCorsConfigurationSource(handler)) {
            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;
    }


    @Nullable
    protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
    
    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) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }
    
    
}

暴露的getHandlerInternal获取处理器的抽象方法(三个直接子类实现了)

* AbstractHandlerMethodMapping

   底层有一个注册表MappingRegistry,包含了url和HandlerMethod类型处理器的映射,返回的HandlerMethod包含一个方法对应的实例、方法反射对象,方法参数信息等,是以一个类方法维度处理请求

* AbstractUrlHandlerMapping

   底层有一个 Map<String, Object> handlerMap,String表示url,Object是对应的处理对象,这个Object可以是String(会从容器获取)或者其他类型

   例如ParameterizableViewController处理器或者自己实现Controller接口类  

* RouterFunctionMapping

   底层有一个路由表RouterFunction<?> routerFunction(默认为DifferentComposedRouterFunction类型,会收集容器中RouterFunction类型的实例,作为一个路由表

   通过对请求的匹配,返回一个匹配的Optional<HandlerFunction<T>>函数指针用于处理请求

AbstractHandlerMethodMapping<T>

概述

* AbstractHandlerMethodMapping<T>是AbstractHandlerMapping其中一个子类

- 从类名可以知道,基于方法的映射规则抽象类,抽取了基于方法作为映射器的实现规则,是以一个类方法维度处理请求

- 需要注意这个的类的泛型T,,表示的是一个mapping,其包含了一个处理器匹配的请求信息,如请求url、请求方法、请求头指定

  例如一个@RequestMapping方法A,那么@RequestMapping注解里所有指定的信息即为mapping,方法就为此mapping对应的处理器

* 其底层有一个注册表MappingRegistry,包含了url和HandlerMethod类型处理器的映射

HandlerMethod包含一个方法对应的实例、方法反射对象,方法参数信息等

* 在afterPropertiesSet调用initHandlerMethods进行初始化方法处理器:

- 遍历容器中的所有类型,执行子类的isHandler(beanType)决定此类是否为Handler(比如@Contrller注解的类),是的话执行detectHandlerMethods方法,

- 会找到指定类的所有方法method和其对应的映射信息到Map<Method, T>  T表示mapping,其包含了一个处理器方法匹配的请求信息,如请求url、请求方法、请求头指定

T需要调用抽象方法getMappingForMethod()获取一个Method的mapping;

- 最后执行this.mappingRegistry.register(mapping, handler, method)先注册到mappingRegistry中

* 实现了getHandlerInternal返回HandlerMethod具体类型,黑色加粗需要子类实现或重写

  ①通过UrlPathHelper().getLookupPathForRequest(request)先获取当前request的url路径

②在urlLookup中获取对应的T mapping

  - urlLookup表注册了直接明确url和T mapping信息的映射

  - 调用addMatchingMappings方法对mapping和request进行进一步的详细匹配,比如对请求方法、producer\consumer的匹配

    进一步匹配的逻辑由子类实现getMatchingMapping方法  

    - 即时是明确的url,同样会再次匹配@RequestMapping中的headers, params, produces, consumes, methods,这一步可能是的直接url匹配的结果为false从而走③

      例如:虽然url一样,当时请求算要求的响应格式是json,而此处理器只返回xml。这就不匹配了

③如果②获取不到,那就选择mappingRegistry表,调用addMatchingMappings方法对mapping和request进行进一步的详细匹配,

④获取最终匹配的mapping,有多个就进行排序,比较规则有抽象方法getMappingComparator()提供

  排序后,前2个是相等的,报错

  ⑤如果最佳匹配只有一个

- 先执行handleMatch方法对最终选择的T mapping,进行一些额外处理,子类可以重写,此类默认实现只做了lookupPath的request属性设置

      handleMatch(bestMatch.mapping, lookupPath, request);

- 返回T mapping对应的HandlerMethod

⑥如果没有找到对应的映射对象调用抽象方法handleNoMatch(),子类可以重写,此类默认返回null

* 暴露的抽象方法

//判断一个类是否为处理器类
protected abstract boolean isHandler(Class<?> beanType);

//获取一个处理器方法对于的映射信息T mapping
@Nullable
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);

//获取映射信息T mapping中的路径,包括模式匹配
protected abstract Set<String> getMappingPathPatterns(T mapping);

//使用T mapping和请求request进行详细的匹配,不单单是url的匹配,还有参数、请求头等
@Nullable
protected abstract T getMatchingMapping(T mapping, HttpServletRequest request);

//获取最终匹配的mapping,有多个就进行排序,比较规则
protected abstract Comparator<T> getMappingComparator(HttpServletRequest request);

afterPropertiesSet收集所有处理器方法到mappingRegistry

* 遍历容器中的所有类型实例,执行子类的isHandler(beanType)决定此类是否为Handler(比如@Contrller注解的类),是的话执行detectHandlerMethods方法,
  protected abstract boolean isHandler(Class<?> beanType);

* detectHandlerMethods方法

- 会找到指定类的所有方法method和其对应的映射信息到Map<Method, T>  T表示mapping,其包含了一个处理器方法匹配的请求信息,如请求url、请求方法、请求头指定

- T需要调用抽象方法getMappingForMethod()获取一个Method的mapping;
   protected abstract T getMappingForMethod(Method method, Class<?> handlerType);

* 最后执行this.mappingRegistry.register(mapping, handler, method)先注册到mappingRegistry中(见上),维护到如下映射关系对象中

- 注册了T mapping信息和HandlerMethod的映射

private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

  - 注册了直接明确url(路径上不存在模式匹配)和T mapping信息的映射

private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

  - 注册了类名+方法名和T mapping信息的映射

private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>()

- 把T mapping、handlerMethod、directUrls、name封装到MappingRegistration中

    加入registry表 T mapping -> MappingRegistration

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

protected void initHandlerMethods() {
   for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         processCandidateBean(beanName);
      }
   }
   handlerMethodsInitialized(getHandlerMethods());
}

protected void processCandidateBean(String beanName) {
   Class<?> beanType = null;
   try {
      beanType = obtainApplicationContext().getType(beanName);
   }
   catch (Throwable ex) {}
   if (beanType != null && isHandler(beanType)) {
      detectHandlerMethods(beanName);
   }
}


protected void detectHandlerMethods(Object handler) {
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException();
               }
            });
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);

//mappingRegistry.register(mapping, handler, method);
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}

MappingRegistry映射注册表

* 里面存有多种维度的映射关系表

- 注册了T mapping信息和HandlerMethod的映射

private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

  - 注册了直接明确url和T mapping信息的映射

private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

  - 注册了类名+方法名和T mapping信息的映射

private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>()

- 把T mapping、handlerMethod、directUrls、name封装到MappingRegistration中

    加入registry表 T mapping -> MappingRegistration

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();

* 注册一个T mapping映射类方法method的过程,register(T mapping, Object handler, Method method)

  - 加锁,进行线程安全控制

  - 把类handler、方法method反射信息到HandlerMethod,new HandlerMethod(handler, method);handler表示方法所在的类实例

    此时的HandlerMethod仅仅只包含了类handler、方法method两个信息

  - 验证T mapping唯一性,使用T mapping的equals,在mappingLookup以及存在就不能再注册了

  - 加入mappingLookup表 T mapping -> HandlerMethod

    this.mappingLookup.put(mapping, handlerMethod);

- 从T mapping找出明确的url,使用抽象方法getMappingPathPatterns(T mapping)获取此mapping所有封装的url

    过滤出非模式匹配的,加入urlLookup表 directUrls -> T mapping

this.urlLookup.add(url, mapping);

例如存在路径参数的就属于模式匹配,此时就不会加入urlLookup

- 使用命名策略,一般为类名.方法名,加入nameLookup表 name -> handlerMethod

    addMappingName(name, handlerMethod);

  - 跨域处理,略

  - 把T mapping、handlerMethod、directUrls、name封装到MappingRegistration中

    加入registry表 T mapping -> MappingRegistration

    
class MappingRegistry {
    //T mappinghandlerMethoddirectUrlsname封装到MappingRegistration
    //加入registry T mapping -> MappingRegistration
    private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
    //注册了 mapping信息和HandlerMethod的映射
    private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
    //注册了直接明确urlmapping信息的想、映射
    private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
    //注册了类名+方法名和mapping信息的想、映射
    private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
    private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

   

    public void register(T mapping, Object handler, Method method) {
        // Assert that the handler method is not a suspending one.

        this.readWriteLock.writeLock().lock();
        try {
            //封装了类、方法反射信息到HandlerMethod
            HandlerMethod handlerMethod = createHandlerMethod(handler, method);
            //验证T mapping唯一性,使用T mappingequals
            validateMethodMapping(handlerMethod, mapping);
            //加入mappingLookup T mapping -> HandlerMethod
            this.mappingLookup.put(mapping, handlerMethod);

            //T mapping找出明确的url,使用抽象方法getMappingPathPatterns(T mapping)获取此mapping所有封装的url
            //过滤出非模式匹配的
            //加入urlLookup directUrls -> T mapping
            List<String> directUrls = getDirectUrls(mapping);
            for (String url : directUrls) {
                this.urlLookup.add(url, mapping);
            }

            //使用命名策略,一般为类名.方法名
            //加入nameLookup name -> handlerMethod
            String name = null;
            if (getNamingStrategy() != null) {
                name = getNamingStrategy().getName(handlerMethod, mapping);
                addMappingName(name, handlerMethod);
            }

            //
            CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
            if (corsConfig != null) {
                this.corsLookup.put(handlerMethod, corsConfig);
            }

            //T mappinghandlerMethoddirectUrlsname封装到MappingRegistration
            //加入registry T mapping -> MappingRegistration
            this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration<>(mapping, handlerMethod, directUrls, name));
        }
        finally {
            this.readWriteLock.writeLock().unlock();
        }
    }
    
    private List<String> getDirectUrls(T mapping) {
        List<String> urls = new ArrayList<>(1);
        for (String path : getMappingPathPatterns(mapping)) {
            if (!getPathMatcher().isPattern(path)) {
                urls.add(path);
            }
        }
        return urls;
    }

    private void addMappingName(String name, HandlerMethod handlerMethod) {
        List<HandlerMethod> oldList = this.nameLookup.get(name);
        if (oldList == null) {
            oldList = Collections.emptyList();
        }

        for (HandlerMethod current : oldList) {
            if (handlerMethod.equals(current)) {
                return;
            }
        }

        List<HandlerMethod> newList = new ArrayList<>(oldList.size() + 1);
        newList.addAll(oldList);
        newList.add(handlerMethod);
        this.nameLookup.put(name, newList);
    }

    public void unregister/removeMappingName(T mapping) {
        //
    }

    
}


private static class MappingRegistration<T> {

    private final T mapping;

    private final HandlerMethod handlerMethod;

    private final List<String> directUrls;

    @Nullable
    private final String mappingName;

    //....
}

实现getHandlerInternal返回HandlerMethod具体类型

HandlerMethod类型

* 返回的类型是HandlerMethod,包含方法的信息,如下

   
public class HandlerMethod {

    //方法对应的bean实例
    private final Object bean;
    @Nullable
    private final BeanFactory beanFactory;

    //bean的类型
    private final Class<?> beanType;
    //方法反射对象
    private final Method method;
    //桥架方法
    private final Method bridgedMethod;
    //方法参数
    private final MethodParameter[] parameters;

    //@responseStatus注解的属性内容
    @Nullable
    private HttpStatus responseStatus;
    @Nullable
    private String responseStatusReason;

    //二次封装时,底层的HandlerMethod
    @Nullable
    private HandlerMethod resolvedFromHandlerMethod;

    //获取此方法,对应所有接口上方法标注的所有注解信息
    @Nullable
    private volatile List<Annotation[][]> interfaceParameterAnnotations;

    private final String description;
    
    }

getHandlerInternal实现逻辑 

  ①通过UrlPathHelper().getLookupPathForRequest(request)先获取当前request的url路径

在直接路径表urlLookup中获取对应的T mapping

  - urlLookup表注册了直接明确url和T mapping信息的映射

  - 调用addMatchingMappings方法对mapping和request进行进一步的详细匹配,比如对请求方法、producer\consumer的匹配

    进一步匹配的逻辑由子类实现getMatchingMapping方法  

    在RequestMappingInfoHandlerMapping中使用遍历每一个RequestMappingInfo的getMatchingCondition(request);进行动态匹配

③如果②获取不到,那就选择mappingRegistry表,调用addMatchingMappings方法对mapping和request进行进一步的详细匹配,会进行url动态的模式匹配

④获取最终匹配的mapping,有多个就进行排序,比较规则有抽象方法getMappingComparator()提供

  排序后,前2个是相等的,报错

  ⑤如果最佳匹配只有一个

- 先执行handleMatch方法对最终选择的T mapping,进行一些额外处理,子类可以重写,此类默认实现只做了lookupPath的request属性设置

      handleMatch(bestMatch.mapping, lookupPath, request);

- 返回T mapping对应的HandlerMethod

⑥如果没有找到对应的映射对象调用抽象方法handleNoMatch(),子类可以重写,此类默认返回null

 
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取请求路径url
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        //匹配此url对应的最佳HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    //存储最佳候选封装了T mapping和HandlerMethod
    List<Match> matches = new ArrayList<>();
    //urlLookup表中获取T mapping
    //urlLookup表注册了直接明确urlT mapping信息的映射
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //mappingrequest进行进一步的详细匹配,比如对请求方法、producer\consumer的匹配
        addMatchingMappings(directPathMatches, matches, request);
    }
    //如果urlLookup表中没有,那就直接在mappingRegistry表,里面包含所有注册进来的mapping->method映射
    //例如存在模式匹配的mapping就在里面
    if (matches.isEmpty()) {
        //mappingrequest进行详细匹配,比如对请求方法、producer\consumer的匹配
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        //排序,调用抽象方法getMappingComparator获取比较器
        Comparator<Match> comparator = new MatchComparator((request));
        matches.sort(comparator);
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            //option跨域询问的请求,直接返回空处理器new HandlerMethod(new EmptyHandler(), ClassUtils.getMethod(EmptyHandler.class, "handle"));
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            //排序后,前2个是相等的,报错
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                throw new IllegalStateException( "Ambiguous handler methods mapped ");
            }
        }
        //缓存以下封装了T mapping和HandlerMethod
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);

//处理最终选择的T mapping,进行一些额外处理
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        //return null;
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
    for (T mapping : mappings) {
        //子类实现getMatchingMapping,返回的是最终完整的T match(和mapping是同一个类型)
        T match = getMatchingMapping(mapping, request);
        if (match != null) {
            matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
        }
    }
}

RequestMappingInfoHandlerMapping

概述

* 主要定义个泛型T mapping的类型为RequestMappingInfo,也是抽象类当时没有暴露抽象方法

* 实现了AbstractHandlerMethodMappin的一些重写方法,例如

- 基于基于RequestMappingInfo实现了getMatchingMapping()和getMappingComparator()方法

- 重写handleMatch()对匹配的映射对象进行后续处理,比如处理路径参数和矩阵参数的解析、producibleMediaTypes属性存于request的属性中

- 重写handleNoMatch()没有找到对应的映射对象调用抽象方法,找到进一步匹配不符合的原因,作为异常提示,抛出异常给用户

  例如url虽然匹配,当时Contentype,即Consumes不匹配,就会作为异常的提示

RequestMappingInfo映射条件信息

* 表示的是一个处理器方法对应的映射信息,客户请求只有匹配了这些映射信息,才能由对应的处理器处理

* RequestMappingInfo和XXXRequestCondition实现了同一个接口

  RequestMappingInfo是基于底层的多个XXXRequestCondition对象实现了RequestCondition接口

RequestMappingInfo

 
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

   @Nullable
   private final String name;
   private final PatternsRequestCondition patternsCondition;
   private final RequestMethodsRequestCondition methodsCondition;
   private final ParamsRequestCondition paramsCondition;
   private final HeadersRequestCondition headersCondition;
   private final ConsumesRequestCondition consumesCondition;
   private final ProducesRequestCondition producesCondition;
   private final RequestConditionHolder customConditionHolder;


   public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns,
         @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params,
         @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes,
         @Nullable ProducesRequestCondition produces, @Nullable RequestCondition<?> custom) {

      this.name = (StringUtils.hasText(name) ? name : null);
      this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
      this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
      this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
      this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
      this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
      this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
      this.customConditionHolder = new RequestConditionHolder(custom);
   }

   ....

}

XXXRequestCondition映射条件
概述

* 使用了RequestCondition类型类封装各种条件

  - PatternsRequestCondition:url路径条件,包括模式匹配

  - RequestMethodsRequestCondition:指定请求方法匹配条件,可多个

  - ParamsRequestCondition:指定请求参数匹配条件,可多个

  - HeadersRequestCondition :指定请求头匹配条件,可多个

  - ConsumesRequestCondition:指定请求头Content-Type匹配条件,可多个

  - ProducesRequestCondition:指定请求头Accept匹配条件,可多个

  - RequestConditionHolder:用户自定义的匹配条件,可多个,底层为如上的RequestCondition

* 每一个XXXRequestCondition实现类,也实现了RequestMappingInfo接口方法

  - 其底层包含一个带匹配的变量,表示条件,如果没有此变量只为空

例如HeadersRequestCondition(代码见下)中的private final Set<HeaderExpression> expressions;成员,”token=xxxx”就会封装为HeaderExpression加入expressions

  - 实现getMatchingCondition(HttpServletRequest request)方法:遍历每一个expressions,调用match(request),只有一个不匹配就返回null

for (HeaderExpression expression : this.expressions) {

if (!expression.match(request)) {

return null;

}

}

  - 实现compareTo方法:由自己的顺序比较规则

public final class HeadersRequestCondition extends AbstractRequestCondition<HeadersRequestCondition> {

    private static final HeadersRequestCondition PRE_FLIGHT_MATCH = new HeadersRequestCondition();
    
    private final Set<HeaderExpression> expressions;
    
    @Override
    @Nullable
    public HeadersRequestCondition getMatchingCondition(HttpServletRequest request) {
        if (CorsUtils.isPreFlightRequest(request)) {
            return PRE_FLIGHT_MATCH;
        }
        for (HeaderExpression expression : this.expressions) {
            if (!expression.match(request)) {
                return null;
            }
        }
        return this;
    }


    @Override
    public int compareTo(HeadersRequestCondition other, HttpServletRequest request) {
        int result = other.expressions.size() - this.expressions.size();
        if (result != 0) {
            return result;
        }
        return (int) (getValueMatchCount(other.expressions) - getValueMatchCount(this.expressions));
    }

   ...

}

PatternsRequestCondition路径URL匹配条件

* 在RequestMappingHandlerMapping实现类中

- 实现了抽象方法getMappingForMethod方法,会去解析每一个@RequestMapping注解,最终形成RequestMappingInfo

- 其中.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))方法就是创建此RequestMappingInfo的PatternsRequestCondition属性

  ①收集到@RequestMapping注解上path或者value上指定的路径数组,路径是可能是模式路径

    ②使用EmbeddedValueResolver解析路径上的${}占位符

      例如 @RequestMapping(value = "restful/${server.port}", method = RequestMethod.GET)

      会解析为 @RequestMapping(value = "restful/8080", method = RequestMethod.GET)


//RequestMappingInfoHandlerMapping
protected RequestMappingInfo createRequestMappingInfo(
    RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

    RequestMappingInfo.Builder builder = RequestMappingInfo
        //使用this.embeddedValueResolver.resolveStringValue(patterns[i]);解析所有模式串
        .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
        .methods(requestMapping.method())
        .params(requestMapping.params())
        .headers(requestMapping.headers())
        .consumes(requestMapping.consumes())
        .produces(requestMapping.produces())
        .mappingName(requestMapping.name());
    if (customCondition != null) {
    builder.customCondition(customCondition);
    }
    return builder.options(this.config).build();
}

//把必要信息封装到PatternsRequestCondition

PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
          this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
         this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
         this.options.getFileExtensions());

* Spring MVC提供如下几种模式匹配的url

  - /resources/ima?e.png :匹配单路径段中的一个字符

  - /resources/*.png :匹配单路径段中的零个或多个字符

  - /resources/** :匹配多个路径段

  - /projects/{project}/versions :匹配单路径段并将其【捕获为变量】

  - /projects/{project:[a-z]+}/versions :使用正则表达式匹配并【捕获变量】

注:? 表示请求单个字符;  * 零个或者多个字符; ** 表示匹配多个字段

* 匹配方式优先级,从上往下,优先级减少

①全路径匹配,例如:配置路由/a/b/c

②带有{}路径的匹配,例如:/a/{b}/c

③正则匹配,例如:/a/{regex:\d{3}}/c

④带有路径的匹配,例如:/a/b/

⑤带有**路径的匹配,例如:/a/b/**

重写getMatchingMapping和getMappingComparator

基于RequestMappingInfo 的getMatchingCondition和compareTo方法实现


//RequestMappingInfoHandlerMapping
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
    return info.getMatchingCondition(request);
}
//RequestMappingInfoHandlerMapping
@Override
protected Comparator<RequestMappingInfo> getMappingComparator(final HttpServletRequest request) {
    return (info1, info2) -> info1.compareTo(info2, request);
}

* RequestMappingInfo的getMatchingCondition和compareTo方法都是基于底层多个XXXRequestCondition实现的

  在之前的步骤,匹配到多个结果时List<Match> ,使用此方法进行排序

* getMatchingCondition方法

- 需要匹配所有的XXXRequestCondition条件,只有一个不匹配就返回null

- 需要匹配的条件:请求方法 -> 请求参数 -> 请求头 -> 请求ContenType -> 请求Accept -> 请求url -> 用户自定义


public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
   RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
   if (methods == null) {
      return null;
   }
   ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
   if (params == null) {
      return null;
   }
   HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
   if (headers == null) {
      return null;
   }
   ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
   if (consumes == null) {
      return null;
   }
   ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
   if (produces == null) {
      return null;
   }
   PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
   if (patterns == null) {
      return null;
   }
   RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
   if (custom == null) {
      return null;
   }

   return new RequestMappingInfo(this.name, patterns,
         methods, params, headers, consumes, produces, custom.getCondition());
}

* compareTo方法实现

  - 比较两个mappingInfo,映射条件也是由顺序的,只有能比较出大小,就不必走下面的比较的

  - 比较顺序为:HEAD方法特定 -> 请求路径 -> 请求参数 -> 请求头 -> 请求ContenType -> 请求Accept -> 请求方法 -> 用户自定义


public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
   int result;
   // Automatic vs explicit HTTP HEAD mapping
   if (HttpMethod.HEAD.matches(request.getMethod())) {
      result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
      if (result != 0) {
         return result;
      }
   }
   result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.producesCondition.compareTo(other.getProducesCondition(), request);
   if (result != 0) {
      return result;
   }
   // Implicit (no method) vs explicit HTTP method mappings
   result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
   if (result != 0) {
      return result;
   }
   result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
   if (result != 0) {
      return result;
   }
   return 0;
}

* RequestMappingHandlerMapping

  基于@RequstMapping的最终实现类,主要实现抽象方法为getMappingForMethod获取一个Method的T mapping;

- getMappingForMethod()获取RequestMappingInfo

@RequestMapping(value = "/list", headers = "",consumes = "")
@ResponseBody
public List<User> list() {
         //..
         return List<User> users = userService.list();;
}

重写handleMatch()

* 对匹配的映射对象进行后续处理,比如处理路径参数decodedUriVariables和矩阵参数matrixVars的解析、producibleMediaTypes属性存于request的属性中

- request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);

- request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);

* 路径参数

@RequestMapping(value="/weibo/{username}/{id}",method=GET)

public String show(

@PathVariable("username") String username,

@PathVariableMap<String,String> map //可获取所有的路径参数

) { }

接收url: http://localhost:8080/weibo/kaka/123

则参数username为kaka,id为123

也支持正则表达式

@RequestMapping(value="/user/{id:正则表达式}")

如:@RequestMapping(value="/user/{id:\\d+}")   表示id的值只能为数字

* 矩阵参数

- Servlet或者Spring都会在映射到servlet或控制器之前会把路径参数去掉,对于@RequestMapping来说是不用匹配路径参数。

例如含路径参数的url:http://localhost:8080/hotel/43;floor=7;room=15/guest

实际上进行匹配的url为http://localhost:8080/hotel/43/guest

而举证参数;floor=7;room=15不参与比较,

- 可使用@MatriVariable获取路径参数

@RequestMapping("hotel/{hotelId/guest}")   //只考虑路径段

public String spittles(

@RequestParam("hotelId") int hotelId,

@MatriVariable(pathVar="hotelId "value="floor") int floor,  

//pathVar:路径参数的key,value是矩阵参数的key

@MatriVariable(pathVar="hotelId "value="room") int room

) { }

@Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
   super.handleMatch(info, lookupPath, request);

   String bestPattern;
   Map<String, String> uriVariables;

   Set<String> patterns = info.getPatternsCondition().getPatterns();
   if (patterns.isEmpty()) {
      bestPattern = lookupPath;
      uriVariables = Collections.emptyMap();
   }
   else {
      bestPattern = patterns.iterator().next();
      uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
   }

   request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);

   if (isMatrixVariableContentAvailable()) {
      Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
      request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
   }

   Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
   request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);

   if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
      Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
      request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
   }
}

private boolean isMatrixVariableContentAvailable() {
   return !getUrlPathHelper().shouldRemoveSemicolonContent();
}

private Map<String, MultiValueMap<String, String>> extractMatrixVariables(
      HttpServletRequest request, Map<String, String> uriVariables) {

   Map<String, MultiValueMap<String, String>> result = new LinkedHashMap<>();
   uriVariables.forEach((uriVarKey, uriVarValue) -> {

      int equalsIndex = uriVarValue.indexOf('=');
      if (equalsIndex == -1) {
         return;
      }

      int semicolonIndex = uriVarValue.indexOf(';');
      if (semicolonIndex != -1 && semicolonIndex != 0) {
         uriVariables.put(uriVarKey, uriVarValue.substring(0, semicolonIndex));
      }

      String matrixVariables;
      if (semicolonIndex == -1 || semicolonIndex == 0 || equalsIndex < semicolonIndex) {
         matrixVariables = uriVarValue;
      }
      else {
         matrixVariables = uriVarValue.substring(semicolonIndex + 1);
      }

      MultiValueMap<String, String> vars = WebUtils.parseMatrixVariables(matrixVariables);
      result.put(uriVarKey, getUrlPathHelper().decodeMatrixVariables(request, vars));
   });
   return result;
}

重写handleNoMatch()

* 找到进一步匹配不符合的原因,作为异常提示,抛出异常给用户

* 例如url虽然匹配,当时Contentype,即Consumes不匹配,就会作为异常的提示

@Override
protected HandlerMethod handleNoMatch(
      Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {

   PartialMatchHelper helper = new PartialMatchHelper(infos, request);
   if (helper.isEmpty()) {
      return null;
   }

   if (helper.hasMethodsMismatch()) {
      Set<String> methods = helper.getAllowedMethods();
      if (HttpMethod.OPTIONS.matches(request.getMethod())) {
         HttpOptionsHandler handler = new HttpOptionsHandler(methods);
         return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
      }
      throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods);
   }

   if (helper.hasConsumesMismatch()) {
      Set<MediaType> mediaTypes = helper.getConsumableMediaTypes();
      MediaType contentType = null;
      if (StringUtils.hasLength(request.getContentType())) {
         try {
            contentType = MediaType.parseMediaType(request.getContentType());
         }
         catch (InvalidMediaTypeException ex) {
            throw new HttpMediaTypeNotSupportedException(ex.getMessage());
         }
      }
      throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes));
   }

   if (helper.hasProducesMismatch()) {
      Set<MediaType> mediaTypes = helper.getProducibleMediaTypes();
      throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes));
   }

   if (helper.hasParamsMismatch()) {
      List<String[]> conditions = helper.getParamConditions();
      throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap());
   }

   return null;
}

RequestMappingHandlerMapping

概述

* 直接继承RequestMappingInfoHandlerMapping,功能等同于父类

  主要实现了其父父类AbstractHandlerMethodMapping的抽象方法isHandler和getMappingForMethod

* 是基于@RequestMapping注解的解析

@RequestMapping/@Controller注解

* @RequestMapping注解内部的属性一一对应了RequestMappingInfo映射条件信息

* @Controller注解是一个标志作用的Component

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {


   String name() default "";
   @AliasFor("path")
   String[] value() default {};
   @AliasFor("value")
   String[] path() default {};
   RequestMethod[] method() default {};
   String[] params() default {};
   String[] headers() default {};
   String[] consumes() default {};
   String[] produces() default {};
}

@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Mapping {

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

   @AliasFor(annotation = Component.class)
   String value() default "";

}

重写isHandler方法

只有存在@RequestMapping/@Controller注解的类都会作为方法处理器类候选,之后会进一步把类中方法解析成T mapping

建立好一些映射关系后会使用this.mappingRegistry.register(mapping, handler, method)先注册到mappingRegistry中


@Override
protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

重写getMappingForMethod方法解析@RequestMapping注解

* 获取方法上RequestMapping注解的信息,使用createRequestMappingInfo方法创建方法维度上的RequestMappingInfo

  RequestMappingInfo info = createRequestMappingInfo(method);

* 获取类上RequestMapping注解的信息,使用createRequestMappingInfo方创建类维度上的RequestMappingInfo

* 合并方法和类上的RequestMappingInfo,即类RequestMappingInfo.combine(方法RequestMappingInfo),各个部分合并的逻辑

   - PatternsRequestCondition:结合 (类上 + 方法上) 两个的路径,

       /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html

       /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar

       /hotels/* + /booking -> /hotels/booking

       /hotels/* + booking -> /hotels/booking

       /hotels/** + /booking -> /hotels/**/booking

       /hotels/** + booking -> /hotels/**/booking

   - RequestMethodsRequestCondition/HeadersRequestCondition/ParamsRequestCondition:合并两者的指定的条件集合

   - ConsumesRequestCondition/ProducesRequestCondition:优先取方法上的配置

* 前缀路径的处理

  - 用户可以配置Map<String, Predicate<Class<?>>>

  - 当Predicate此类为true时,取key作为字符串使用embeddedValueResolver.resolveStringValue(prefix)进行$占位符处理,会从环境配置中取值

  
在配置文件中定义动态动态改变的路径
mvc.url.perfix = /test

@RestController
@RequestMapping("${mvc.url.perfix}/sayhi")
public class HelloController {
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String sayHello(){}

}


public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
        implements MatchableHandlerMapping, EmbeddedValueResolverAware {

    //创建RequestMappingInfo时的BuilderConfiguration配置设置
    private boolean useSuffixPatternMatch = true;
    private boolean useRegisteredSuffixPatternMatch = false;
    private boolean useTrailingSlashMatch = true;
    private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap<>();
    private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
    @Nullable
    private StringValueResolver embeddedValueResolver;
    private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();


    @Override
    public void afterPropertiesSet() {
        this.config = new RequestMappingInfo.BuilderConfiguration();
        this.config.setUrlPathHelper(getUrlPathHelper());
        this.config.setPathMatcher(getPathMatcher());
        this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
        this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
        this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
        this.config.setContentNegotiationManager(getContentNegotiationManager());

        super.afterPropertiesSet();
    }


    @Override
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
    }

    @Override
    @Nullable
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        //获取方法上RequestMapping注解的信息,创建方法维度上的RequestMappingInfo
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            //获取类上RequestMapping注解的信息,创建类维度上的RequestMappingInfo
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                //合并方法和类上的RequestMappingInfo
                // - PatternsRequestCondition:结合类上和方法上两种的路径,
                //   /* + /hotel -> /hotel ; "/*.*" + "/*.html" -> /*.html
                //   /user + /user -> /usr/user ; /{foo} + /bar -> /{foo}/bar
                //   /hotels/* + /booking -> /hotels/booking
                //   /hotels/* + booking -> /hotels/booking
                //   /hotels/** + /booking -> /hotels/**/booking
                //   /hotels/** + booking -> /hotels/**/booking
                // - RequestMethodsRequestCondition/HeadersRequestCondition/ParamsRequestCondition:合并两者的指定的条件集合
                // - ConsumesRequestCondition/ProducesRequestCondition:优先取方法上的配置
                info = typeInfo.combine(info);
            }
            //前缀路径的处理
            //用户可以配置Map<String, Predicate<Class<?>>>
            //Predicate此类为true时,取key作为字符串使用embeddedValueResolver.resolveStringValue(prefix)进行$占位符处理
            String prefix = getPathPrefix(handlerType);
            if (prefix != null) {
                info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
            }
        }
        return info;
    }

    @Nullable
    String getPathPrefix(Class<?> handlerType) {
        for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
            if (entry.getValue().test(handlerType)) {
                String prefix = entry.getKey();
                if (this.embeddedValueResolver != null) {
                    prefix = this.embeddedValueResolver.resolveStringValue(prefix);
                }
                return prefix;
            }
        }
        return null;
    }


    @Nullable
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition<?> condition = (element instanceof Class ?
                getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }
    @Nullable
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        return null;
    }
    @Nullable
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        return null;
    }

    protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

        RequestMappingInfo.Builder builder = RequestMappingInfo
                //使用this.embeddedValueResolver.resolveStringValue(patterns[i]);解析所有模式串
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                .methods(requestMapping.method())
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name());
        if (customCondition != null) {
            builder.customCondition(customCondition);
        }
        return builder.options(this.config).build();
    }



    @Override
    public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
        super.registerMapping(mapping, handler, method);
        updateConsumesCondition(mapping, method);
    }

    //获取@RequestBody注解的required赋值给ConsumesRequestCondition
    private void updateConsumesCondition(RequestMappingInfo info, Method method) {
        ConsumesRequestCondition condition = info.getConsumesCondition();
        if (!condition.isEmpty()) {
            for (Parameter parameter : method.getParameters()) {
                MergedAnnotation<RequestBody> annot = MergedAnnotations.from(parameter).get(RequestBody.class);
                if (annot.isPresent()) {
                    condition.setBodyRequired(annot.getBoolean("required"));
                    break;
                }
            }
        }
    }


    ....
}

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐