public interface MatchableHandlerMapping extends HandlerMapping {
/** * 判断请求和指定 `pattern` 路径是否匹配的接口方法 * * Determine whether the given request matches the request criteria. * @param request the current request * @param pattern the pattern to match * @return the result from request matching, or {@code null} if none */ @Nullable RequestMatchResult match(HttpServletRequest request, String pattern);
/** * 匹配上的路径 */ private final String matchingPattern;
/** * 被匹配的路径 */ private final String lookupPath;
/** * 路径匹配器 */ private final PathMatcher pathMatcher;
/** * Create an instance with a matching pattern. * @param matchingPattern the matching pattern, possibly not the same as the * input pattern, e.g. inputPattern="/foo" and matchingPattern="/foo/". * @param lookupPath the lookup path extracted from the request * @param pathMatcher the PathMatcher used */ public RequestMatchResult(String matchingPattern, String lookupPath, PathMatcher pathMatcher) { Assert.hasText(matchingPattern, "'matchingPattern' is required"); Assert.hasText(lookupPath, "'lookupPath' is required"); Assert.notNull(pathMatcher, "'pathMatcher' is required"); this.matchingPattern = matchingPattern; this.lookupPath = lookupPath; this.pathMatcher = pathMatcher; }
/** * Extract URI template variables from the matching pattern as defined in * {@link PathMatcher#extractUriTemplateVariables}. * @return a map with URI template variables */ public Map<String, String> extractUriTemplateVariables() { return this.pathMatcher.extractUriTemplateVariables(this.matchingPattern, this.lookupPath); }
/** * 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";
/** Detect all HandlerMappings or just expect "handlerMapping" bean?. */ private boolean detectAllHandlerMappings = true;
/** List of HandlerMappings used by this servlet. */ @Nullable private List<HandlerMapping> handlerMappings;
// <1> 如果开启探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings 中 if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. // 扫描已注册的 HandlerMapping 的 Bean 们 Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); // 添加到 handlerMappings 中,并进行排序 if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } // <2> 如果关闭探测功能,则获得 HANDLER_MAPPING_BEAN_NAME 对应的 Bean 对象,并设置为 handlerMappings } else { 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. // <3> 如果未获得到,则获得默认配置的 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"); } } }
/** * Name of the class path resource (relative to the DispatcherServlet class) * that defines DispatcherServlet's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
/** * 默认配置类 */ private static final Properties defaultStrategies;
static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { // 初始化 defaultStrategies 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()); } }