HandlerMapping在这个SpringMVC体系结构中有着举足轻重的地位,充当着url和Controller之间映射关系配置的角色。主要有三部分组成:HandlerMapping映射注册、根据url获取对应的处理器、拦截器注册。
看下HandlerMapping的继承结构:
由图中可以看出HandlerMapping家族分两支,一支继承AbstractUrlHandlerMapping,另一支继承AbstractHandlerMethodMapping,而这两支都继承自AbstractHandlerMapping。
AbstractHandlerMapping
初始化
AbstractHandlerMapping是HandlerMapping的抽象实现,所有的HandlerMapping都继承自AbstractHandlerMapping。AbstractHandlerMapping采用模板形式设计了HandlerMapping实现的整体结构,子类只需要通过模板方法提供一些初始值和算法。
PS:在SpringMVC中模板形式是最常见的,首先使用一个抽象类在顶层设计好功能结构,子类继承去实现。这种方法在很多框架中都很重要。
AbstractHandlerMapping继承自WebApplicationObjectSupport,所以其初始化方法为initApplicationContext()。
Interceptor为拦截器
extendInterceptors()是一个模板方法,用于子类增加Interceptor,不过SpringMVC中并没有使用。
detectMappedInterceptors()用于将SpringMVC容器及其父容器中所有类型为MappedInterceptor类型的拦截器添加到HandlerMapping的mappedInterceptors属性之中。
initInterceptors()的作用是初始化Interceptor,具体的内容是按照interceptors属性中的Interceptor按照类型分类到mappedInterceptors和adaptedInterceptors之中。
getHandler
HandlerMapping是通过getHandler来获取Handler和Interceptor的
getHandler的步骤:(1)从模板方法getHandlerInternal中找, 如果找不到,(2)使用defaultHandler,defaultHandler是配置HandlerMapping的时候设置的,如果找到的Handler是String类型,那么去Spring容器中找同名的Bean作为handler。(3)执行getHandlerExecutionChain(handler, request)
首先创建HandlerExecutionChain变量,之后将所有的AdaptedInterceptors和符合要求的mappedInterceptor加入到HnadlerExecutionChain之中并返回。
AbstractUrlHandlerMapping
AbstractUrlHanderMapping是通过url来匹配Handler的,主要的方式就是将url和handler存入到一个本地的handlerMap属性之中,另外还单独定义了处理”/”请求的rootHandler
AbstractHandlerMapping之中设计了子类获取handler的接口为getInternalHandler
需要看下lookupHandler和buildPathExposingHandler
buildPathExposingHandler方法用于给查找到的Handler注册两个拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor,这两个是内部拦截器,主要作用就是将当前url实际匹配的pattern,匹配条件以及url模板参数等设置到request的属性之中,这样后面的处理过程就可以直接从request的属性中获取。而不需要再查找一遍了。
handlerMap的初始化
handlerMap的初始化通过registerHandler方法进行,这个方法承担AbstractUrlHandlerMapping的创建工作(handler初始化),不过并不是自己调用,而是给子类调用。
注册很简单,看map里面原来有没有传入url,如果没有就put进去,有就检测一下是不是同一个handler,如果不同就是Exception了,总不能相同的url对应两个不同的hadler吧。同事要注意一下,rootHandler(”/”)和defaultHandler(“/*”)的使用。
SimpleUrlHandlerMapping
SimpleUrlHandlerMapping自己定义了一个Map变量,这样做的有两个作用,第一是方便配置,第二是可以在注册前做一些预处理,比如确保url的格式。将所有的url和handler对应关系放入这个Map后再注册到父类的Map之中。SimpleUrlHandlerMapping创建的时候通过重写父类的initApplicationContext方法调用了registerHandlers方法完成Handler的注册。
最后调用的registerHandler就是父类AbstractUrlHandlerMapping中的方法。
AbstractDetectingUrlHandlerMapping
获取容器中的bean如果能解析到url那么调用父类的registerHandler方法注册。
如何解析到url使用方法determineUrlsForHandler()是一个模板方法,子类具体实现。
从继承结构中看AbstractDetectingUrlHandlerMapping有两个子类BeanNameUrlHandlerMapping,AbstractControllerUrlHandlerMapping
BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping只有一个方法,重写了determineUrlsForHandler(String beanName),判定规则为beanName的开头是不是”/”,并且搜寻了bean的所有alias。
AbstractControllerUrlHandlerMapping
AbstractControllerUrlHandlerMapping是将实现了Controller接口或者注释了@Controller的bean作为Handler,并且通过设置了excludePackages和excludedClasses将不包含的bean和不包含的包下面的所有bean排除在外。主要是将handler找出来,具体使用什么url在模板方法buildUrlsForHandler中由子类实现
注意使用什么url有模板方法buildUrlsForHandler确定
isControllerType(beanClass)判定该bean是不是controller
看下AbstractControllerUrlHandlerMapping的两个子类:
AbstractHandlerMethodMapping系列
AbstractHandlerMethodMapping系列是将Method作为Handler来使用的,这也是我们现在用的最多的一种Handler,比如@RequstMapping注释的Method就是这种Handler。
弄清楚AbstractHandlerMethodMapping最为关键的是弄清楚其定义的三个Map的含义
模板参数T表示一种匹配Handler的条件的类
看一下子类中的使用
RequestMappingInfo实现了RequestCondition接口,此接口专门保存从request提取出来的用于匹配Handler的条件
AbstarcatRequestCondition重写了equals(),hashCode(),toString()三个方法,其有8个子类,除了CompositeCondition,每个子类表示一种匹配条件。比如PatternRequestCondition使用url做匹配,RequestMethodRequestCondition使用RequestMethod做匹配等。CompositeRequestCondition本身并不实际做匹配,而是可以将多个别的RequestCondition封装到自己的一个变量里,在用的时候遍历封装RequestCondition的那个变量里所有的RequestCondition进行匹配,这个就是责任链模式。这种模式在SpringMVC之中非常常见,一般就是命名为CompositeXXX或者XXXComposite,主要的左右就是为了方便调用。
RequstCondition的另一个实现就是这里要说的RequestMappingInfo,它其实是用七个变量保存了七个RequstCondition,在匹配时使用那七个变量进行匹配,这也就是可以在@RequestMapping中给处理器指定多种匹配方式的原因。
具体的代码分析就略过了。
现在说下AbstractHandlerMethodMapping的三个Map
handlerMethods: