天天看点

Spring MVC-HandlerMapping

Spring MVC 使用HandlerMapping来找到并保存url请求和处理函数间的mapping关系。

以DefaultAnnotationHandlerMapping为例来具体看HandlerMapping的作用

DefaultAnnotationHandlerMapping将扫描当前所有已经注册的spring beans中的@requestmapping标注以找出url 和 handler method处理函数的关系并予以关联。

一般我们都是用Spring中配置的默认的HandlerMapping:BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,下面我们就分析这两个类的源代码。

  • BeanNameUrlHandlerMapping

    首先看这个类的继承关系

    Spring MVC-HandlerMapping

    对于《接口——抽象类——实现类》这种代码书写风格在Spring中到处可见,很简单,接口就是对使用者声明的服务,声明了是一定要实现。下面的所有类(抽象的、具体的)都是为了实现接口中方法而设计的。

    抽象类是为了将具体类中的公共的部分抽离出来——代码的复用。

    那么分析这种结构就从接口中声明的方法一点一点往类中渗透,HandlerMapping中声明的方法是

    HandlerExecutionChain getHandler(HttpServletRequest request)

    ,首先看第一级抽象继承类AbstractHandlerMapping中默认实现,这个类中有存放【拦截器】的成员变量List interceptors
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中 
        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 = getApplicationContext().getBean(handlerName);
        }
        //生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。  
        return getHandlerExecutionChain(handler, request);
}
           

通过代码我们知道关键代码是

Object handler = getHandlerInternal(request);

这个方法具体实现是在接口的二级抽象子类AbstractUrlHandlerMapping,这个类中有存放【request请求和Handler的映射关系】的成员变量Map handlerMap

找到关键性代码:

// 这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。          
List<String> matchingPatterns = new ArrayList<String>();           
for (String registeredPattern : this.handlerMap.keySet()) {        
    if (getPathMatcher().match(registeredPattern, urlPath)) {      
        matchingPatterns.add(registeredPattern);                   
    }                                                              
} 
………………………………
//这里根据匹配路径找到最象的一个
if (bestPatternMatch != null) {
    handler = this.handlerMap.get(bestPatternMatch);  
………………………………
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);                                                               
           

至此你需要的接口中声明的方法返回的HandlerExecutionChain已经得到,那么大家一定会问,对于第三四级继承AbstractDetectingUrlHandlerMapping和BeanNameUrlHandlerMapping是做什么用的。他们的作用就是侦测Spring的bean工厂中的所有的handler存储到AbstractUrlHandlerMapping的成员变量Map handlerMap中。存储的方法是

registerHandler(String urlPath, Object handler)

if (urlPath.equals("/")) {                                                                                                                    
    setRootHandler(resolvedHandler);                                      
}
else if (urlPath.equals("/*")) {                                                                                                                      
    setDefaultHandler(resolvedHandler);                                        
} 
else {                                              
     //把url和handler的对应关系放到handlerMap中去             
    this.handlerMap.put(urlPath, resolvedHandler); 
    ……………………                                                                                                                                                       
           

至此HandlerMapping的解析完成,但是我们发现这个类的继承关系类中都是从bean工厂直接得到handler,那么这些handler是什么时候放到bean工厂的那?这就要在《Spring IOC》相关文章中分享。

继续阅读