Spring MVC 使用HandlerMapping来找到并保存url请求和处理函数间的mapping关系。
以DefaultAnnotationHandlerMapping为例来具体看HandlerMapping的作用
DefaultAnnotationHandlerMapping将扫描当前所有已经注册的spring beans中的@requestmapping标注以找出url 和 handler method处理函数的关系并予以关联。
一般我们都是用Spring中配置的默认的HandlerMapping:BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,下面我们就分析这两个类的源代码。
-
BeanNameUrlHandlerMapping
首先看这个类的继承关系
对于《接口——抽象类——实现类》这种代码书写风格在Spring中到处可见,很简单,接口就是对使用者声明的服务,声明了是一定要实现。下面的所有类(抽象的、具体的)都是为了实现接口中方法而设计的。
抽象类是为了将具体类中的公共的部分抽离出来——代码的复用。
那么分析这种结构就从接口中声明的方法一点一点往类中渗透,HandlerMapping中声明的方法是
,首先看第一级抽象继承类AbstractHandlerMapping中默认实现,这个类中有存放【拦截器】的成员变量List interceptorsHandlerExecutionChain getHandler(HttpServletRequest request)
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》相关文章中分享。