SpringMVC 分析(二) handlerMapping 家族

来源:互联网 发布:人工智能大会2017 编辑:程序博客网 时间:2024/05/18 09:58

再次承接上文。

为什么直接从AbstractHandlerMethodMapping入手呢?其实通过上篇可以发现 HandlerMethod 这个map中记录了超多的关于一个Method的信息,并且能够直接匹配到具体的Method,也是现在应用比较多的一种方式。就比如如下格式。在一个RequestMapping内部可以定义很多关于这个请求的格式,应用较好。

@Controller

@RequestMapping(/student)

public Class Student{


@RequestMaping(/addStudent ,method = {RequestMethod.GET},produces="application/json;charset=UTF-8")

public addStudent(){

}

}

今天既然去看了Mapping的家族,自然不能少了他们的继承关系。关系图如下,也是直接盗图过来。


顶层接口 HandleerMapping,左分支就是上篇博客研究的 AbstractHandlerMethodMapping ,有分支暂时不想去看,任性~~~~~~。

上篇研究了一下它的初始化,知道了它是如何记录当前系统中的Method的映射关系。今天就可以去研究 是如何去解析request,知道最终找到合适的Handler了。


protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
.....
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);


在DispatcherServlet中,最终会获得的是一个HandlerExecutionChain ,是通过getHandler去获取的,而 getHandler 接口就是定义在它们的老祖宗HandleerMapping中。

由子类实现,而handlerMapping 中getHandlerInternal又是由 其子类AbstractHandlerMethodMapping  实现,所以直接关注AbstractHandlerMethodMapping 中的方法

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}

HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
}

lookupPath  顾名思义就是这次请求的url了。不管。

来看lookupHandlerMethod

只看关键代码,其他忽略:

List<T> directPathMatches = this.urlMap.get(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
}

urlMap 在这边出现,这个里面记录了 url 和匹配条件的全部信息。addMatchingMappings 没去看,因为本身请求的格式都有后缀,类似.htm 或者 .do,这边的话肯定是没有的

。一开始还纳闷呢,结果发现之后只能说自己太二了。

if (matches.isEmpty()) {
// No choice but to go through all mappings
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
}

结果自然是到addMatchingMappings ,找到对应的Method, 至于匹配过程的话,其实猜都可以猜到,上篇匹配条件记录了很多东西,url信息,头信息等等。那么这边的match信息的话就有可能会找到多个匹配的Method,这是很正常的。

Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
....
Match bestMatch = matches.get(0);

结果不言而喻,当时看到这边时也在想可定是有排序的。spring的话直接取第一条匹配的作为bestMatch返回。。。。。


最后的话 调用  handlerMethod.createWithResolvedBean()

创建出这个handler bean返回 给最初的 HandlerExecutionChain。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}

这段在DispatcherServlet内。至此,一次请求从分发到mapping 到handler的创建,结束。接下来就是研究 HandlerExecutionChain是个什么东西了,它接下去会做什么。下篇再说吧。

至于在handlermapping之前初始化好的一些拦截器啊什么的,暂时就不关注了,spring mvc 那么大,先沿着一条线走下去,看看都能学到些什么东西。hh


0 0