springMVC源码简读——2.2 HandlerMapping的解析器(上)

    xiaoxiao2021-04-15  235

    整理完之后发现放在一章太长了,于是截断了。上:主要是介绍HandlerMapping 接口、抽象实现类、以及基于URL实现业务的HandlerMapping

    概述

    顶级接口

    处理器匹配接口,根据请求( handler )获得其的处理器( handler )和拦截器们( HandlerInterceptor 数组 ) 其顶级接口是

    public interface HandlerMapping { String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler"; 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; }

    类图

    接口HandlerMapping的类图关系

    实现类

    AbstractHandlerMapping

    继承 WebApplicationObjectSupport 抽象类,HandlerMapping抽象基类,实现了【获得请求对应的处理器和拦截器们】的骨架逻辑

    构造方法

    // AbstractHandlerMapping.java /** * 默认处理器 */ @Nullable private Object defaultHandler; /** * URL 路径工具类 */ private UrlPathHelper urlPathHelper = new UrlPathHelper(); /** * 路径匹配器 */ private PathMatcher pathMatcher = new AntPathMatcher(); /** * 配置的拦截器数组. * * 添加方式有两种: * * 1. {@link #setInterceptors(Object...)} 方法 * 2. {@link #extendInterceptors(List)} 方法 */ private final List<Object> interceptors = new ArrayList<>(); /** * 初始化后的拦截器 HandlerInterceptor 数组 */ private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>(); /** * 顺序,最低优先级 */ private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered /** * Bean 名字 */ @Nullable private String beanName;

    initApplicationContext

    初始化拦截器

    // AbstractHandlerMapping.java @Override protected void initApplicationContext() throws BeansException { // 空方法。交给子类实现,用于注册自定义的拦截器到 interceptors 中。目前暂无子类实现。 extendInterceptors(this.interceptors); // 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中 detectMappedInterceptors(this.adaptedInterceptors); // 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中 initInterceptors(); } // 扫描所有已经注册到容器中的MappedInterceptor类 protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) { // 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中 // MappedInterceptor 会根据请求路径做匹配,是否进行拦截。 mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( obtainApplicationContext(), MappedInterceptor.class, true, false).values()); }

    initInterceptors

    将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中

    protected void initInterceptors() { if (!this.interceptors.isEmpty()) { // 遍历 interceptors 数组 for (int i = 0; i < this.interceptors.size(); i++) { // 获得 interceptor 对象 Object interceptor = this.interceptors.get(i); if (interceptor == null) { throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); } // 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中 // 注意,HandlerInterceptor 无需进行路径匹配,直接拦截全部 this.adaptedInterceptors.add(adaptInterceptor(interceptor)); } } } protected HandlerInterceptor adaptInterceptor(Object interceptor) { // HandlerInterceptor 类型,直接返回 if (interceptor instanceof HandlerInterceptor) { return (HandlerInterceptor) interceptor; } // WebRequestInterceptor 类型,适配成 WebRequestHandlerInterceptorAdapter 对象,然后返回 else if (interceptor instanceof WebRequestInterceptor) { return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor); } // 错误类型,抛出 IllegalArgumentException 异常 else { throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName()); } }

    getHandler

    获得请求对应的hand执行链,这个请求在3.1中介绍请求过程的代码中会调用到,是handlerMapping 的核心之一

    // AbstractHandlerMapping.java public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 获得处理器。该方法是抽象方法,由子类实现 Object handler = getHandlerInternal(request); if (handler == null) { // 获得不到,则使用默认处理器 handler = getDefaultHandler(); } // 还是获得不到,则返回 null if (handler == null) { return null; } // Bean name or resolved handler? // <4> 如果找到的处理器是 String 类型,则从容器中找到 String 对应的 Bean 类型作为处理器。 // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; // 从上下文中获得handler handler = obtainApplicationContext().getBean(handlerName); } // 获得 HandlerExecutionChain 对象 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // 打印日志 if (logger.isTraceEnabled()) { logger.trace("Mapped to " + handler); } else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) { logger.debug("Mapped to " + executionChain.getHandler()); } if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } // 返回 return executionChain; }

    getHandlerInternal是获得handler的方法,基类不实现,子类实现。

    getHandlerExecutionChain

    获得处理器执行链

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { // 创建 HandlerExecutionChain 对象 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); // 获得请求路径 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); // 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器 for (HandlerInterceptor interceptor : this.adaptedInterceptors) { // 需要匹配,若路径匹配,则添加到 chain 中 if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } // 无需匹配,直接添加到 chain 中 else { chain.addInterceptor(interceptor); } } return chain; }

    MatchableHandlerMapping

    基于HandlerMapping 接口的扩展。定义判断请求和指定 pattern 路径是否匹配的接口方法

    public interface MatchableHandlerMapping extends HandlerMapping { /** * 判断请求和指定 `pattern` 路径是否匹配的接口方法 */ @Nullable RequestMatchResult match(HttpServletRequest request, String pattern); }

    RequestMatchResult

    匹配结果的封装对象,包含了匹配值,被匹配值,和匹配器参数

    public class RequestMatchResult { /** * 匹配上的路径 */ private final String matchingPattern; /** * 被匹配的路径 */ private final String lookupPath; /** * 路径匹配器 */ private final PathMatcher pathMatcher; 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; } public Map<String, String> extractUriTemplateVariables() { return this.pathMatcher.extractUriTemplateVariables(this.matchingPattern, this.lookupPath); } }

    初始化

    初始化的地方还是在DispatcherServlet没得说,方法是initHandlerMappings,一样的套路,优先判断扫描,然后从容器中获取,假如都没有则使用默认值

    private void initHandlerMappings(ApplicationContext context) { // 置空 handlerMappings this.handlerMappings = null; // 如果开启探测功能,则扫描已注册的 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); } } // 如果关闭探测功能,则获得 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. // 如果未获得到,则获得默认配置的 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"); } } }

    实现类-基于 URL 进行匹配

    AbstractUrlHandlerMapping

    以 URL 作为 Handler 的 HandlerMapping 抽象类,提供 Handler 的获取 注意是org.springframework.web.servlet.handler下的

    构造函数

    // AbstractUrlHandlerMapping.java /** * 处理器 */ @Nullable private Object rootHandler; /** * 使用后置匹配 */ private boolean useTrailingSlashMatch = false; /** * 是否延迟加载 */ private boolean lazyInitHandlers = false; /** * 路径和处理器映射 */ private final Map<String, Object> handlerMap = new LinkedHashMap<>();

    registerHandler

    注册多个URL的处理器

    // AbstractUrlHandlerMapping.java protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { Assert.notNull(urlPaths, "URL path array must not be null"); // 循环路径数组 for (String urlPath : urlPaths) { // 将路径和类进行注册 registerHandler(urlPath, beanName); } } protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; // Eagerly resolve handler if referencing singleton via name. // 如果非延迟加载,并且 handler 为 String 类型 if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; ApplicationContext applicationContext = obtainApplicationContext(); // 如果是单例的就去容器中获得处理器 if (applicationContext.isSingleton(handlerName)) { resolvedHandler = applicationContext.getBean(handlerName); } } // 从已经加载的映射集合中获取url对应的处理器 Object mappedHandler = this.handlerMap.get(urlPath); // 如果已经存在,并且和 resolvedHandler 不同,代表一个url映射了两个处理器, // 则抛出 IllegalStateException 异常 if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException( "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); } } else { // 如果是根路径则设置根处理器RootHandler if (urlPath.equals("/")) { if (logger.isTraceEnabled()) { logger.trace("Root mapping to " + getHandlerDescription(handler)); } setRootHandler(resolvedHandler); } // 如果是/*则设置默认处理器 else if (urlPath.equals("/*")) { if (logger.isTraceEnabled()) { logger.trace("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler); } // 将路径映射添加到集合中 else { this.handlerMap.put(urlPath, resolvedHandler); if (logger.isTraceEnabled()) { logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler)); } } } }

    在下面的实现可以发现,整个路径处理器的注册就是根据路径和bean名称,先通过bean名称获得bean然后将映射添加到映射集合中。

    getHandlerInternal

    获得处理器,根据路径去上面的集合中获得,路径匹配的处理器

    // AbstractUrlHandlerMapping.java protected Object getHandlerInternal(HttpServletRequest request) throws Exception { // 获得请求路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 通过路径去集合中获得处理器 Object handler = lookupHandler(lookupPath, request); // 如果处理器为空 if (handler == null) { // We need to care for the default handler directly, since we need to // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well. Object rawHandler = null; // 假如是根路径获得根处理器 if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } // 还是空,则取默认处理器 if (rawHandler == null) { rawHandler = getDefaultHandler(); } // 假如还是没有定位到,这判断是否字符串 // 假如是就去容器中拿 if (rawHandler != null) { // Bean name or resolved handler? if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = obtainApplicationContext().getBean(handlerName); } validateHandler(rawHandler, request); // 创建处理器 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } return handler; }

    lookupHandler

    获得处理器

    // AbstractUrlHandlerMapping.java protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? // 直接在集合中获得处理器 Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? // 如果找到的处理器是 String 类型,则从容器中找到 String 对应的 Bean 类型作为处理器。 if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // Pattern match? // Pattern 正则匹配合适的,并添加到 matchingPatterns 中 List<String> matchingPatterns = new ArrayList<>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) { matchingPatterns.add(registeredPattern + "/"); } } } String bestMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); // 假如匹配的结果不为空,进行排序然后获得第一个结果 if (!matchingPatterns.isEmpty()) { matchingPatterns.sort(patternComparator); if (logger.isTraceEnabled() && matchingPatterns.size() > 1) { logger.trace("Matching patterns " + matchingPatterns); } bestMatch = matchingPatterns.get(0); } // 匹配到最佳路径 if (bestMatch != null) { handler = this.handlerMap.get(bestMatch); if (handler == null) { if (bestMatch.endsWith("/")) { handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1)); } if (handler == null) { throw new IllegalStateException( "Could not find handler for best pattern match [" + bestMatch + "]"); } } // Bean name or resolved handler? // 如果找到的处理器是 String 类型,则从容器中找到 String 对应的 Bean 类型作为处理器。 if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them // 获得路径参数集合 Map<String, String> uriTemplateVariables = new LinkedHashMap<>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestMatch, matchingPattern) == 0) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) { logger.trace("URI variables " + uriTemplateVariables); } // 创建处理器 return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }

    buildPathExposingHandler

    主要给处理器注册两个拦截器PathExposingHandlerInterceptor,UriTemplateVariablesHandlerInterceptor;当前url实际匹配的Pattern、匹配条件和url模板参数设置到request的属性

    // AbstractUrlHandlerMapping.java protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) { // 创建 HandlerExecutionChain 对象 HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); // 将路径和映射拼装成拦截器,添加HandlerExecutionChain中 chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping)); // 添加 UriTemplateVariablesHandlerInterceptor 拦截器,到 chain 中 if (!CollectionUtils.isEmpty(uriTemplateVariables)) { chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables)); } return chain; }

    match

    执行匹配

    // AbstractUrlHandlerMapping.java public RequestMatchResult match(HttpServletRequest request, String pattern) { // 获得请求路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 假如匹配返回【匹配对象 if (getPathMatcher().match(pattern, lookupPath)) { return new RequestMatchResult(pattern, lookupPath, getPathMatcher()); } else if (useTrailingSlashMatch()) { if (!pattern.endsWith("/") && getPathMatcher().match(pattern + "/", lookupPath)) { return new RequestMatchResult(pattern + "/", lookupPath, getPathMatcher()); } } // 否则返回null return null; }

    为handler注册的两个拦截器

    PathExposingHandlerInterceptor

    设置url路径匹配数据

    private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter { /** * 最佳路径 */ private final String bestMatchingPattern; /** * 被匹配的路径 */ private final String pathWithinMapping; public PathExposingHandlerInterceptor(String bestMatchingPattern, String pathWithinMapping) { this.bestMatchingPattern = bestMatchingPattern; this.pathWithinMapping = pathWithinMapping; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 将最佳路径和被匹配路径设置到request中 exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request); // 将handler设置到request request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, handler); // 否支持类型级别映射 request.setAttribute(INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings()); return true; } } UriTemplateVariablesHandlerInterceptor

    设置url模板参数

    private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter { /** * url 模板参数 */ private final Map<String, String> uriTemplateVariables; public UriTemplateVariablesHandlerInterceptor(Map<String, String> uriTemplateVariables) { this.uriTemplateVariables = uriTemplateVariables; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 将模板参数设置到request中 exposeUriTemplateVariables(this.uriTemplateVariables, request); return true; } }

    SimpleUrlHandlerMapping

    继承 AbstractUrlHandlerMapping 抽象类,UrlHandlerMapping 实现类

    构造函数

    // SimpleUrlHandlerMapping.java /** * url 和 处理器的映射 */ private final Map<String, Object> urlMap = new LinkedHashMap<>();

    initApplicationContext

    进行初始化

    // SimpleUrlHandlerMapping.java public void initApplicationContext() throws BeansException { super.initApplicationContext(); // 初始化路径的映射关系 registerHandlers(this.urlMap); }

    AbstractDetectingUrlHandlerMapping

    继承 AbstractUrlHandlerMapping 抽象类,自动探测的 UrlHandlerMapping 抽象实现类

    initApplicationContext

    进行初始化,调用父类进行初始化,但是他注册映射关系使用的是

    // AbstractDetectingUrlHandlerMapping.java public void initApplicationContext() throws ApplicationContextException { super.initApplicationContext(); // 自动探测 detectHandlers(); } protected void detectHandlers() throws BeansException { // 从容器中获得类名 ApplicationContext applicationContext = obtainApplicationContext(); String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : applicationContext.getBeanNamesForType(Object.class)); // Take any bean name that we can determine URLs for. // 遍历 Bean ,逐个注册 for (String beanName : beanNames) { // 根据类名获得url数组 String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // 逐一祖册 // URL paths found: Let's consider it a handler. registerHandler(urls, beanName); } } if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) { logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName()); } }

    然而determineUrlsForHandler并没有实现,所以需要看他的子类

    BeanNameUrlHandlerMapping

    基于 Bean 的名字来自动探测的 HandlerMapping 实现类

    // BeanNameUrlHandlerMapping.java public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { /** * Checks name and aliases of the given bean for URLs, starting with "/". */ @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<>(); // 如果是以 / 开头,添加到 urls if (beanName.startsWith("/")) { urls.add(beanName); } // 获得bean的别名假如以/开头则添加到urls中 String[] aliases = obtainApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); } }

    这个…………我还没想明白是什么场景使用的


    最新回复(0)