Spring-MVC 源码分析(三):HandleMapping的配置与实现

 

Java代码 HandleMapping接口
public interface HandlerMapping {  
  
    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";  
  
      
    String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";  
  
  
    String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";  
  
    //通过getHandler实际上返回的是一个HanderExecutionChain,这是一个典型的Command  模式的使用,这个HandleExecutionChain不但持有handler本身,还包括了处理这个HTTP请求相关的拦截器
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;  
  
}  
 

 

HandleMapping的子类继承结构图


Spring-MVC 源码分析(三):HandleMapping的配置与实现_第1张图片

以SimpleUrlHandlerMapping为例


Spring-MVC 源码分析(三):HandleMapping的配置与实现_第2张图片

 

第一步: org.springframework.context.ApplicationContextAware

Java代码 ApplicationContextAware
   public interface ApplicationContextAware {  
       
     //这个方法的目的实现了这个接口的bean在初始化之后会自动注入ApplicationContext实例
     void setApplicationContext(ApplicationContext applicationContext) throws BeansException;  
  
}  
 
第二步: org.springframework.context.support.ApplicationObjectSupport 

Java代码 实现 ApplicationObjectSupport # setApplicationContext(ApplicationContext context)
public final void setApplicationContext(ApplicationContext context) throws BeansException {  
        if (context == null && !isContextRequired()) {  
            // Reset internal context state.  
            this.applicationContext = null;  
            this.messageSourceAccessor = null;  
        }  
        else if (this.applicationContext == null) {  
            // 如果传入的context不是ApplicationContext的实例,则抛出异常
            if (!requiredContextClass().isInstance(context)) {  
                throw new ApplicationContextException(  
                        "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");  
            }  
            this.applicationContext = context;  
            this.messageSourceAccessor = new MessageSourceAccessor(context);  
             //初始化占位符方法,可由子类重写
            initApplicationContext(context);  
        }  
        else {  
            // Ignore reinitialization if same context passed in.  
            if (this.applicationContext != context) {  
                throw new ApplicationContextException(  
                        "Cannot reinitialize with different application context: current one is [" +  
                        this.applicationContext + "], passed-in one is [" + context + "]");  
            }  
        }  
    }  
 

第三步:org.springframework.web.context.ServletContextAware

Java代码 ServletContextAware接口
public interface ServletContextAware {  
   // 实现该接口的bean初始化后自动注入ServletContext实例
    void setServletContext(ServletContext servletContext);  
  
}   
  

第四步: org.springframework.web.context.support.WebApplicationObjectSupport

Java代码 实现 WebApplicationObjectSupport # setServletContext(ServletContextservletContext)
public final void setServletContext(ServletContext servletContext) {  
    if (servletContext != this.servletContext) {  
        this.servletContext = servletContext;  
        if (servletContext != null) { 
            //占位符方法,子类可重写实现 
            initServletContext(servletContext);  
        }  
    }  
}  
 

Java代码 重写父类ApplicationObjectSupport # initApplicationContext(ApplicationContext context)方法
@Override  
protected void initApplicationContext(ApplicationContext context) {  
    //调用父类的initApplicationContext
    super.initApplicationContext(context);  
    if (this.servletContext == null && context instanceof WebApplicationContext) {  
        this.servletContext = ((WebApplicationContext) context).getServletContext();  
        if (this.servletContext != null) {  
            initServletContext(this.servletContext);  
        }  
    }  
}  
 

第五步:org.springframework.web.servlet.handler.AbstractHandlerMapping

     抽象处理器映射是处理器映射实现中的最底层的实现,它直接实现处理器映射接口,并且继承Web应用程序环境支持对象。
     它提供了配置缺省处理器以及应用到所有处理器上的处理器拦截器的功能。

 它把具体如何取得一个处理器抽象并且留给子类进行特殊化的实现。


Java代码 重写了ApplicationObjectSupport # initApplicationContext()方法
@Override  
    protected void initApplicationContext() throws BeansException {  
        //模板方法,交由子类重写.可以扩展新的拦截器对象
        extendInterceptors(this.interceptors);  
       //初始化拦截器,因为拦截器有不同的是是实现,这里需要将不同的拦截器适配到最终的HandlerInterceptor的是实现,这是通过HandlerInterceptorAdapter来实现的
        initInterceptors();  
    }  
 

Java代码 AbstractHandlerMapping # initInterceptors()

protected void initInterceptors() {  
         //如果配置的通用拦截器不为空  
        if (!this.interceptors.isEmpty()) { 
             //对配置的通用拦截器进行适配  
            this.adaptedInterceptors = new HandlerInterceptor[this.interceptors.size()];  
            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");  
                }  
               //适配给定的interceptor
                this.adaptedInterceptors[i] = adaptInterceptor(interceptor);  
            }  
        }  
    } 
 

Java代码 AbstractHandlerMapping # adaptInterceptor(Object interceptor)
protected HandlerInterceptor adaptInterceptor(Object interceptor) { 
          //如果拦截器是HandlerInterceptor本身的是实现,不需要适配  
        if (interceptor instanceof HandlerInterceptor) {  
            return (HandlerInterceptor) interceptor;  
        } 
          //如果拦截器是WebRequestHandlerIntercepto,则适配到通用的HandlerInterceptor的实现  
        else if (interceptor instanceof WebRequestInterceptor) {  
            return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);  
        }  
        // //不支持其他类型的拦截器
        else {  
            throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());  
        }  
    }  
 

Java代码 AbstractHandlerMapping # getHandler(HttpServletRequest request) 也是HandlerMapping接口getHandler方法的实现

//实现处理器映射的方法,这个方法是派遣器Servlet要求翻译HTTP请求到处理器执行链的入口  
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
        //使用某种映射逻辑,将请求映射到一个真正的处理器,这个方法定义为抽象的,子类必须实现它,例如,实现基于URL到Beean名称的映射逻辑  
        Object handler = getHandlerInternal(request);  
          //如果请求指定的处理没找到,则使用默认的
        if (handler == null) {  
            /子类可以设置缺省的处理器,也可以通过注射的方式设置缺省的处理器  
            handler = getDefaultHandler();  
        }  
         //如果没有发现任何处理器,则返回空处理器, 派遣器Servlet将发送HTTP错误响应SC_NOT_FOUND(404)  
        if (handler == null) {  
            return null;  
        }  
        // 如果handler是字符串类型,,则认为这个字符串是Bean的名字  
        if (handler instanceof String) {  
            String handlerName = (String) handler;  
            //在应用程序环境中通过Bean名字查找这个Bean 
            handler = getApplicationContext().getBean(handlerName);  
        }  
         //包装处理器和拦截器,返回处理器执行链
        return getHandlerExecutionChain(handler, request);  
    }  
 


Java代码 AbstractHandlerMapping # getHandlerExecutionChain(Object handler,HttpServletRequest request)
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {  
         //判断处理器对象的类型  
        if (handler instanceof HandlerExecutionChain) {  
            //如果处理器已经是处理器执行链对象  
            HandlerExecutionChain chain = (HandlerExecutionChain) handler;  
            //添加初始化的拦截器  
            chain.addInterceptors(getAdaptedInterceptors());  
            return chain;  
        }  
        else {  
            //否则使用处理器和初始化的拦截器构造处理器执行链的对象 
            return new HandlerExecutionChain(handler, getAdaptedInterceptors());  
        }  
    }  
 


第六步:org.springframework.web.servlet.handler.AbstractUrlHandlerMapping

     抽象URL处理器映射继承自抽象处理器映射,实现了取得一个处理器的抽象方法,提供了功能根据URL进行匹配处理器的功能。
     也提供了根据 URL 查找应用在处理器上特殊的拦截器。并且提供了方法实现注册 URL 到处理器的映射。
     如何获得URL到处理器的映射的逻辑留给子类进行完成。

Java代码 AbstractUrlHandlerMapping # initInterceptors() 重写了父类 AbstractHandlerMapping # initInterceptors()
@Override  
    //改写了抽象处理器的拦截器初始化的方法,初始化更多配置在Web应用程序环境中的映射拦截器,映射拦截器是一个从URL到处理器拦截器对象映射的实现
    protected void initInterceptors() {  
        //初始化父类的通用拦截器,这些拦截器应用到所有的处理器上  
        super.initInterceptors();  
        //查找所有在Web应用程序环境中注册的MappedInterceptor的实现 
        Map<String, MappedInterceptor> mappedInterceptors = BeanFactoryUtils.beansOfTypeIncludingAncestors(  
                getApplicationContext(), MappedInterceptor.class, true, false);  
          //如果找到任何MappedInterceptor的实现  
        if (!mappedInterceptors.isEmpty()) {  
            //构造MappedInterceptor的集合类并且存储,这个集合类提供了通过URL过滤拦截器的功能
            this.mappedInterceptors = new MappedInterceptors(mappedInterceptors.values().toArray(  
                    new MappedInterceptor[mappedInterceptors.size()]));  
        }  
  
    }  
 


Java代码 AbstractUrlHandlerMapping # getHandlerInternal(HttpServletRequestrequest) 重写了 父类 AbstractHandlerMapping # getHandlerInternal方法
@Override  
    //实现抽象处理器映射的抽象发放,提供基于URL匹配的实现 
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {  
       // 返回的映射查找给定的请求路径,在当前的servlet映射
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);  
       // 这里使用得到的URL路径对Handler进行匹配,得到对应的Handler。如果没有对应的Handler,返回null,这样默认的handler会被使用
        Object handler = lookupHandler(lookupPath, request);  
        if (handler == null) {  
             //如果没有最佳匹配处理器 
            Object rawHandler = null;  
            if ("/".equals(lookupPath)) {  
                  //如果查找路径是根路径,则使用根处理器 
                rawHandler = getRootHandler();  
            }  
            if (rawHandler == null) {  
                  //否则使用缺省处理器  
                rawHandler = getDefaultHandler();  
            }  
            if (rawHandler != null) {  
               //如果是根路径或者配置了缺省处理器
                if (rawHandler instanceof String) {  
                      //翻译处理器Bean名字到Bean对象本身,如果配置了懒惰加载为false, 而且处理器是单例模式,这个转换在初始化的时候已经做完了 
                    String handlerName = (String) rawHandler;  
                    rawHandler = getApplicationContext().getBean(handlerName);  
                }  
               //定义占位符方法校验处理器  
                validateHandler(rawHandler, request);  
                //增加新的处理器拦截器导出最佳匹配路径和查找路径,既然我们使用了根处理器或者缺省处理器,这两个值都是查找路径  
                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);  
            }  
        }  
        if (handler != null && this.mappedInterceptors != null) {  
            //如果存在最佳匹配处理器,过滤映射拦截器,得到所有匹配的处理器拦截器
            Set<HandlerInterceptor> mappedInterceptors = this.mappedInterceptors.getInterceptors(lookupPath, this.pathMatcher);  
            if (!mappedInterceptors.isEmpty()) {  
                HandlerExecutionChain chain;  
                if (handler instanceof HandlerExecutionChain) {  
                      //如果处理器拦截器是处理器执行链对象,则使用已存对象  
                    chain = (HandlerExecutionChain) handler;  
                }  
                else {  
                    //否则创建新的处理器执行链  
                    chain = new HandlerExecutionChain(handler);  
                }  
                 //添加过滤得到的处理器拦截器到处理器执行链中  
                chain.addInterceptors(mappedInterceptors.toArray(new HandlerInterceptor[mappedInterceptors.size()]));  
            }  
        }  
       //【问题】既然方法开始调用了lookupHandler(),那么返回处理器映射器对象或者null,所以创建新的处理器执行链逻辑不会执行。
       //如果子类改写了lookupHandler()返回一个普通的处理器对象,创建新的处理器执行链逻辑不被执行,但是新的处理器执行链对象没有返回,所以,添加的处理器拦截器将会丢失,这里程序设计有些不妥
        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;  
    }  
 

Java代码 AbstractUrlHandlerMapping # lookupHandler(String urlPath,HttpServletRequest request)
//lookupHandler是根据URL路径,启动在handlerMap中对handler的检索,并最终返回handler对象
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {  
        // 首先执行精确匹配,查找路径和处理器配置的URL完全相同  
        Object handler = this.handlerMap.get(urlPath);  
        if (handler != null) {  
           // 精确匹配成功 
            if (handler instanceof String) {  
               //翻译Bean名到Bean对象本身
                String handlerName = (String) handler;  
                handler = getApplicationContext().getBean(handlerName);  
            }  
          //调用占位符方法校验处理器 
            validateHandler(handler, request);  
          //增加新的处理器拦截器导出最佳匹配路径和查找路径,既然精确匹配成功,这两个值都是查找路径  
            return buildPathExposingHandler(handler, urlPath, urlPath, null);  
        }  
        // 若handler为空
        // 执行最佳匹配方案
        List<String> matchingPatterns = new ArrayList<String>();  
        for (String registeredPattern : this.handlerMap.keySet()) {
          //取得所有匹配的处理器注册的URL Pattern   
            if (getPathMatcher().match(registeredPattern, urlPath)) {  
                matchingPatterns.add(registeredPattern);  
            }  
        } 
        // 自动寻找最优匹配注册路径 
        String bestPatternMatch = null;  
        Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);  
        if (!matchingPatterns.isEmpty()) { 
             //对匹配的URL Pattern进行排序 
            Collections.sort(matchingPatterns, patternComparator);  
            if (logger.isDebugEnabled()) {  
                logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);  
            }  
            //排序后数组的第一个匹配为最佳匹配  
            bestPatternMatch = matchingPatterns.get(0);  
        }  
        if (bestPatternMatch != null) {  
            //如果存在最佳匹配,则找到最佳匹配URL Pattern的处理器
            handler = this.handlerMap.get(bestPatternMatch);  
            // 翻译Bean名到Bean对象本身  
            if (handler instanceof String) {  
                String handlerName = (String) handler;  
                handler = getApplicationContext().getBean(handlerName);  
            }  
               //调用占位符方法校验处理器  
            validateHandler(handler, request);  
            //从URL中提取去除URL Pattern前缀的剩余部分,例如,URL Pattern是/petstore/*,而查找路径是/petstore/insert,则结构是/insert 
            String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);  
  
             //得到模板变量,并且添加新的处理器拦截器到处到HTTP请求中,这些模板变量在控制器的实现中会被用到
             //例如, URL Pattern是/petstore/insert/{id}, 查找路径是insert/1,则解析出一个模板变量id=1,并且到处到HTTP请求对象里 
            Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();  
            for (String matchingPattern : matchingPatterns) {  
                if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {  
                    uriTemplateVariables  
                            .putAll(getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath));  
                }  
            }  
            if (logger.isDebugEnabled()) {  
                logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);  
            }  
             //创建处理器执行链对象
            return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);  
        }  
        // No handler found...  
        return null;  
    } 
 

Java代码 AbstractUrlHandlerMapping # buildPathExposingHandler方法实现
protected Object buildPathExposingHandler(Object rawHandler, 
                   String bestMatchingPattern,
                   String pathWithinMapping, 
                   Map<String, String> uriTemplateVariables) {  
         //创建处理器执行器链对象 
        HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); 
        //添加路径到处理器拦截器,类定义如下   
        chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));  
        if (!CollectionUtils.isEmpty(uriTemplateVariables)) {  
            //添加模板变量处理器拦截器,类定义如下 
            chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));  
        }  
        return chain;  
    }  
 

Java代码 AbstractUrlHandlerMapping 内部类 PathExposingHandlerInterceptor实现
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) {  
            //导出是在处理器拦截器的前置拦截器中实现的  
            exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request);  
            return true;  
        }  
    }  
 


Java代码 AbstractUrlHandlerMapping # exposePathWithinMapping
protected void exposePathWithinMapping(String bestMatchingPattern, String pathWithinMapping, HttpServletRequest request) {  
       //导出到请求属性中,在控制器中这些路径可以用来解析缺省的视图名
        request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatchingPattern);  
        request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);  
    }  
 

Java代码 AbstractUrlHandlerMapping 内部类 UriTemplateVariablesHandlerInterceptor实现
private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter {  
  
        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) {  
              //导出是在处理器拦截器的前置拦截器中实现的  
            exposeUriTemplateVariables(this.uriTemplateVariables, request);  
            return true;  
        }  
    }  
 

Java代码 AbstractUrlHandlerMapping # exposeUriTemplateVariables 方法
protected void exposeUriTemplateVariables(Map<String, String> uriTemplateVariables, HttpServletRequest request) {
         //导出到请求属性中,在控制器中这些参数可能成为业务逻辑的输入   
        request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);  
    }
 

Java代码 AbstractUrlHandlerMapping # registerHandler(String[] urlPaths,String beanName)
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {  
        //注册的处理器必须映射到一个URL路径上  
        Assert.notNull(urlPaths, "URL path array must not be null");  
         //对于拥有多个URL的处理器,分别注册URL到处理器的映射  
        for (String urlPath : urlPaths) {  
            registerHandler(urlPath, beanName);  
        }  
    }  
 

Java代码 AbstractUrlHandlerMapping # registerHandler(String urlPath,Object handler)
//注册一个URL到一个处理器的映射  
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {  
        //URL和处理器都不能为空  
        Assert.notNull(urlPath, "URL path must not be null");  
        Assert.notNull(handler, "Handler object must not be null");  
        //开始解析处理器  
        Object resolvedHandler = handler;  
  
       //如果没有配置懒惰初始化处理器选项,则把使用的处理器名字转换为Web应用程序环境中的Bean  
       //如果配置懒惰初始化处理器选项,则这个转换是在返回处理器执行链的过程中实现的  
        if (!this.lazyInitHandlers && handler instanceof String) {  
            String handlerName = (String) handler;  
             //如果这个Bean使用单例模式,则在初始化的时候进行转换,在后续的服务方法中不再进行转换,提高了效率  
             //但是,如果非单例模式,我们不能在初始化的时候进行转换,
             //例如,如果Bean的范围是Session,服务方法(getHanlderInternal)会的到不同的处理器实例对于不同的Session,在这种情况,如果初始化的时候进行转换,则每次返回同一个Bean,变成了单例模式了  
            if (getApplicationContext().isSingleton(handlerName)) {  
                resolvedHandler = getApplicationContext().getBean(handlerName);  
            }  
        }  
       
        //查看是否这个URL已经注册过处理器了
        Object mappedHandler = this.handlerMap.get(urlPath);  
        if (mappedHandler != null) {  
             //如果这个URL确实已经注册过处理器了  
            if (mappedHandler != resolvedHandler) {  
                //抛出异常,提示用户配置错误  
                throw new IllegalStateException(  
                        "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +  
                        "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");  
            }  
        }  
        else {  
          //如果这个URL没有注册过处理器了  
            if (urlPath.equals("/")) {  
                  //如果是根处理器  
                if (logger.isInfoEnabled()) {  
                    logger.info("Root mapping to " + getHandlerDescription(handler));  
                }  
                 //设置根处理器
                setRootHandler(resolvedHandler);  
            }  
            else if (urlPath.equals("/*")) {  
                 //如果是默认处理器  
                if (logger.isInfoEnabled()) {  
                    logger.info("Default mapping to " + getHandlerDescription(handler));  
                }  
                 //设置默认处理器  
                setDefaultHandler(resolvedHandler);  
            }  
            else {  
                 //设置正常的处理器  
                this.handlerMap.put(urlPath, resolvedHandler);  
                if (logger.isInfoEnabled()) {  
                    logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));  
                }  
            }  
        }  
    } 
 

第七步:org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

这个实现类通过配置一套URL Pattern到处理器的映射而实现的。
它使用配置的映射中的URL Pattern匹配请求中的URL,如果匹配成功,则使用匹配URL Pattern映射的Bean作为处理器返回。

Oh,SimpleUrlHandlerMapping urlMap 是通过手动配置注入的

Java代码 SimpleUrlHandlerMapping # initApplicationContext() 重写了AbstractHandlerMapping # initApplicationContext()方法
@Override  
    public void initApplicationContext() throws BeansException {  
        super.initApplicationContext();  
       //初始化的时候注册处理器
        registerHandlers(this.urlMap);  
    }
 
Java代码 SimpleUrlHandlerMapping # registerHandlers(Map<String,Object> urlMap)方法    
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {  
        if (urlMap.isEmpty()) {
           //如果配置的处理器映射为空,则警告  
            logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");  
        }  
        else {  
            for (Map.Entry<String, Object> entry : urlMap.entrySet()) {  
                String url = entry.getKey();  
                Object handler = entry.getValue();  
                // Prepend with slash if not already present.  
                if (!url.startsWith("/")) { 
                   // 如果url不是以/开头在第一个字符前加/ 
                    url = "/" + url;  
                }  
                // 如果handler是bean名字,去掉前后空格 
                if (handler instanceof String) {  
                    handler = ((String) handler).trim();  
                }  
                // 注册 url 到 handler 的映射
                registerHandler(url, handler);  
            }  
        }  
    } 
 
第八步:Spring-MVC 提供了自动探测发现URL到处理器的映射的实现,抽象类AbstractDetectingUrlHandlerMapping,继承结构图如下

Spring-MVC 源码分析(三):HandleMapping的配置与实现_第3张图片
 

  抽象探测URL处理器映射(AbstractDetectingUrlHandlerMapping)

 

抽象探测URL处理器映射通过一定的规则在Web应用程序环境中自动发现URL到处理器的映射。

 

使用什么样的规则在Web应用程序环境中自动发现URL到处理器的映射并没有直接实现,因为这会有很多的映射规则,并且根据需求可以自由扩展。这个规则留给子类进行实现。

 

BeanURL处理器映射就是根据把Bean名声明作为URL来发现处理器的。而缺省注解处理器映射是根据声明在控制器中的请求映射注解中包含的URL Pattern信息来解析处理器的。




Java代码 AbstractDetectingUrlHandlerMapping # initApplicationContext() 重写 AbstractUrlHandlerMapping # initApplicationContext()方法  
@Override 
    //改写应用程序初始化方法,获得注册处理器的机会 
    public void initApplicationContext() throws ApplicationContextException {  
        //保持原来的初始化实现  
        super.initApplicationContext();  
        //从Web应用程序环境中探测处理器  
        detectHandlers();  
    } 
 

Java代码 AbstractDetectingUrlHandlerMapping # detectHandlers() 
protected void detectHandlers() throws BeansException {  
        if (logger.isDebugEnabled()) {  
            logger.debug("Looking for URL mappings in application context: " + getApplicationContext());  
        }  
        //找到所有的对象类的实现,其实是Web应用程序环境中所有的Bean,并且返回Bean名字  
        String[] beanNames = (this.detectHandlersInAncestorContexts ?  
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :  
                getApplicationContext().getBeanNamesForType(Object.class));  
  
         // 对于每一个Bean的名字
        for (String beanName : beanNames) {  
            //映射Bean的名字到一个或者多个URL 这是一个占位符方法,即beanName到url的映射规则,由子类实现
            String[] urls = determineUrlsForHandler(beanName);  
            if (!ObjectUtils.isEmpty(urls)) {  
                 //如果这个Bean的名字能映射到一个或者多个URL,则注册Bean作为一个处理器  
                registerHandler(urls, beanName);  
            }  
            else {  
                 //否则打印日志  意思是该beanName没有URL
                if (logger.isDebugEnabled()) {  
                    logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");  
                }  
            }  
        }  
    }  
 

第九步: org.springframework.web.servlet.mvc.support.AbstractControllerUrlHandlerMapping


第十步:org.springframework.web.servlet.mvc.support. ControllerBeanNameHandlerMapping


第十一步:  org.springframework.web.servlet.mvc.support. ControllerClassNameHandlerMapping


第十二步:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping



第十三步:org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

这个实现类通过声明在Web应用程序环境中Bean类型中的请求映射注解(@RequestMapping)来注册处理器映射的。请求映射注解声明有匹配请求URL所用的URL Pattern。然后,使用方法级别的请求映射注解中声明的URL Pattern和类型级别的请求映射注解中声明的URL Pattern结合并且匹配请求的URL,如果匹配成功,则使用匹配的Bean作为处理器返回。

Java代码 DefaultAnnotationHandlerMapping #determineUrlsForHandler(String beanName) 重写了 AbstractDetectingUrlHandlerMapping 
@Override  
    protected String[] determineUrlsForHandler(String beanName) {  
        ApplicationContext context = getApplicationContext();  
        Class<?> handlerType = context.getType(beanName);  
        // 得到这个bean的类级别@RequestMapping注解
        RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class);  
        if (mapping != null) {  
            // 类级别有@RequestMapping注解
            // @RequestMapping found at type level  
            this.cachedMappings.put(handlerType, mapping);  
            Set<String> urls = new LinkedHashSet<String>();  
            // 类级别匹配模式
            String[] typeLevelPatterns = mapping.value();  
            if (typeLevelPatterns.length > 0) { 
            // 类级别的@RequestMapping有value值 
                // @RequestMapping specifies paths at type level  
                // 方法级别匹配模式
                String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType, true);  
                for (String typeLevelPattern : typeLevelPatterns) {  
                    if (!typeLevelPattern.startsWith("/")) {  
                        typeLevelPattern = "/" + typeLevelPattern;  
                    }  
                    boolean hasEmptyMethodLevelMappings = false;  
                    for (String methodLevelPattern : methodLevelPatterns) {  
                        if (methodLevelPattern == null) {  
                            hasEmptyMethodLevelMappings = true;  
                        }  
                        else {  
                           // 返回两种模式匹配的组合结果
                            String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern);  
                            addUrlsForPath(urls, combinedPattern);  
                        }  
                    }  
                    if (hasEmptyMethodLevelMappings ||  
                            org.springframework.web.servlet.mvc.Controller.class.isAssignableFrom(handlerType)) {  
                        addUrlsForPath(urls, typeLevelPattern);  
                    }  
                }  
                return StringUtils.toStringArray(urls);  
            }  
            else {  
                // actual paths specified by @RequestMapping at method level  
                // 类级别@RequestMapping没有value值
                return determineUrlsForHandlerMethods(handlerType, false);  
            }  
        }  
        else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {  
            // 类级别没有@RequestMapping注解,但有@Controller注解,检测方法级别
            // @RequestMapping to be introspected at method level  
            return determineUrlsForHandlerMethods(handlerType, false);  
        }  
        else {  
            return null;  
        }  
    } 
 

Java代码 DefaultAnnotationHandlerMapping # deteminUrlsForHandlerMethods 方法
protected String[] determineUrlsForHandlerMethods(Class<?> handlerType, final boolean hasTypeLevelMapping) {  
        // 模板方法,可由子类重现
        String[] subclassResult = determineUrlsForHandlerMethods(handlerType);  
        if (subclassResult != null) {  
            return subclassResult;  
        }  
  
        final Set<String> urls = new LinkedHashSet<String>();  
        Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
        // 包括了父类接口方法@RequestMapping注解  
        handlerTypes.add(handlerType);  
        handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));  
        for (Class<?> currentHandlerType : handlerTypes) {  
            ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {  
                public void doWith(Method method) {  
                    RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);  
                    if (mapping != null) {  
                        String[] mappedPatterns = mapping.value();  
                        if (mappedPatterns.length > 0) {  
                            for (String mappedPattern : mappedPatterns) {  
                                if (!hasTypeLevelMapping && !mappedPattern.startsWith("/")) {  
                                    mappedPattern = "/" + mappedPattern;  
                                }  
                                addUrlsForPath(urls, mappedPattern);  
                            }  
                        }  
                        else if (hasTypeLevelMapping) {  
                            // empty method-level RequestMapping  
                            urls.add(null);  
                        }  
                    }  
                }  
            }, ReflectionUtils.USER_DECLARED_METHODS);  
        }  
        return StringUtils.toStringArray(urls);  
    }  
 


你可能感兴趣的:(mapping)