HandlerMapping(四)AbstractUrlHandlerMapping

分析第二个体系

AbstractUrlHandlerMapping系列

通过url来进行匹配。

此系列的大致原理是

将url和对应的Handler保存在一个Map中,
在getHandlerInternal方法使用url从map中获取Handler。
映射过程自己实现,
而map的初始化交给具体的子类去完成
handlerMap 还有一个处理’/’的rootHandler.

第一步,首先看父类中没有实现的一个方法
getHandlerInternal

    //获取Handler,主要是通过url和method的对应关系来查找  
        @Override  
        protected Object getHandlerInternal(HttpServletRequest request) throws Exception {  
            //获取request中的请求链接  
            String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);  
            //根据链接查找handler  
            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.  
                //定义一个变量,保存找到的原始Handler  
                Object rawHandler = null; 
                //如果lookupPath为"/",使用rootHandler
                if ("/".equals(lookupPath)) {  
                    rawHandler = getRootHandler();  
                }  
                //如果没有使用一个默认的
                if (rawHandler == null) {  
                    rawHandler = getDefaultHandler();  
                }  
                if (rawHandler != null) {  
                    // Bean name or resolved handler?  
                    //如果是String类型则到容器中查找具体的Bean  
                    if (rawHandler instanceof String) {  
                        String handlerName = (String) rawHandler;  
                        rawHandler = getApplicationContext().getBean(handlerName);  
                    }  
                    validateHandler(rawHandler, request);  
                    handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);  
                }  
            }  
            if (handler != null && logger.isDebugEnabled()) {  
                logger.debug("Mapping [" + lookupPath + "] to " + handler);  
            }  
            //没有映射路径
            else if (handler == null && logger.isTraceEnabled()) {  
                logger.trace("No handler mapping found for [" + lookupPath + "]");  
            }  
            return handler;  
        }  

看来从map中获取handler分为两步
1.获取request中的请求链接
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
2.根据请求链接查找handler
Object handler = lookupHandler(lookupPath, request);

首先是通过lookupHandler方法来查找Handler,这里我们看到了之前说的Map对象,用来存储url和Handler之间的关系,当Handler获取为String时需要从Bean容器中获取注入的实现类,当然在查找过程中也会有模糊匹配等查找过程。

来分析一下lookupHandler

    protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {  
            // Direct match?  
            //直接从map中获取  根据key获取value
            Object handler = this.handlerMap.get(urlPath);  
            if (handler != null) {  
                // Bean name or resolved handler?  
                //如果是String类型则从容器中获取  
                if (handler instanceof String) {  
                    String handlerName = (String) handler;  
                    handler = getApplicationContext().getBean(handlerName);  
                }  
                //验证是否合是正确格式
                validateHandler(handler, request);  
                return buildPathExposingHandler(handler, urlPath, urlPath, null);  
            }  
            //在map中没有获取到
            // Pattern match?  
            //通过模糊匹配来查找  
            List<String> matchingPatterns = new ArrayList<String>();  
            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 bestPatternMatch = null;  
            //匹配规则  
            Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);  
            if (!matchingPatterns.isEmpty()) {  
                Collections.sort(matchingPatterns, patternComparator);  
                if (logger.isDebugEnabled()) {  
                    logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);  
                }  
                bestPatternMatch = matchingPatterns.get(0);  
            }  
            if (bestPatternMatch != null) {  
                handler = this.handlerMap.get(bestPatternMatch);  
                if (handler == null) {  
                    Assert.isTrue(bestPatternMatch.endsWith("/"));  
                    handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));  
                }  
                // Bean name or resolved handler?  
                if (handler instanceof String) {  
                    String handlerName = (String) handler;  
                    handler = getApplicationContext().getBean(handlerName);  
                }  
                validateHandler(handler, request);  
                String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, 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<String, String>();  
                for (String matchingPattern : matchingPatterns) {  
                    if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {  
                        Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);  
                        Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);  
                        uriTemplateVariables.putAll(decodedVars);  
                    }  
                }  
                if (logger.isDebugEnabled()) {  
                    logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);  
                }  
                return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);  
            }  
            // No handler found...  
            return null;  
        }  

感觉主要是匹配规则复杂 多看看就明白了
上面两个方法介绍了通过url来查找handlerMap获取handler的操作,AbstractUrlHandlerMapping中也提供了注册url和handler到handlerMap中的操作,具体的调用则要到AbstractUrlHandlerMapping的子类中实现。

通过上面介绍我们知道AbstractUrlHandlerMapping提供的功能就是根据url从handlerMap中获取handler和注册url和handler的对应关系到handlerMap中,当然这个过程中还包含很多其他的操作。

另一个重要方法 bindPathExposingHandler。

第二步 然后是map的初始化
初始化map有两种方式
1. 手工在配置文件中注册
2. 另一种在spring容器里寻找 需要赛选

在registerHandler方法进行,有两个方法

具体子类的实现SimpleUrlHandlerMapping
AbstractDetectingUrlHandlerMapping有3个子类
BeanName AbstractController

AbstractHandlerMethodMapping
只有3个类
RequestMappingInfoHandlerMapping
RequestMappingHandlerMapping

该系列是将Method作为Handler来使用 比如@RequestMapping 所注释的方法就是这种Handler 该系列匹配内容比较多,直接匹配到Method。

器用分析法
内部3个map
handlerMethods
urlMap
nameMap

整个过程使用Match作为载体,内部类封装了匹配条件和HandlerMethod

查找interceptors是通过几个相关map完成

完整代码点这里–》

//******************************************************

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值