SpringMvc源码分析3——HandlerMapping
一. 准备
首先再次贴一下HandlerMapping
结构图:
接着上一篇,我们暴露的接口:
@RestController
public class IndexController {
@GetMapping("/hello")
public String hello(String name) {
return "hello: " + name;
}
}
bebug到DispatcherServlet#doDispatch
:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. todo待分析,关注点一
mappedHandler = getHandler(processedRequest);
// 2. todo待分析,关注点二
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. todo待分析,关注点三
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 4. todo待分析,关注点四
applyDefaultViewName(processedRequest, mv);
// 5. todo待分析,关注点五
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
二. 分析
1. 关注几个属性值
我们先看一下DispatcherServlet
内部几个属性此时的值:
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
handlerMappings
handlerAdapters
handlerExceptionResolvers
viewNameTranslator
viewResolvers
2. 关注点一源码
mappedHandler = getHandler(processedRequest);
这里主要是根据请求找到匹配的HandlerMapping
,然后得到相应的handler
和拦截器,封装成HandlerExecutionChain
返回。
源码:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// todo分析
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
找到的匹配到HandlerMapping
为RequestMappingHandlerMapping
.接着执行:
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 得到handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 获取到请求的拦截器,封装成HandlerExecutionChain返回
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
RequestMappingHandlerMapping
里面维护着mappingRegistry
,它的值为:
其实
mappingRegistry
属性在AbstractHandlerMethodMapping
里面。
然后根据请求找出里面匹配到的RequestMappingInfo
,从而得到HandlerMethod
对象。
最后得到的handler
为:
之后,获取到请求的拦截器,再封装成HandlerExecutionChain返回。对应代码为:
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
三. 总结
HandlerMapping
的作用其实就是请求和具体Handler
处理器(这里的Handler
一般为Controller
里的一个方法method
,或者org.springframework.web.servlet.mvc.Controller
等)之间的一个映射关系。
如SimpleUrlHandlerMapping
则是会根据内部维护的urlMap
(以路径作为键,并以处理程序bean或bean名称作为值的Map)查找具体的handler
。
而RequestMappingHandlerMapping
则会处理请求和注解(@Controller
,@RequestMapping
)方法对应的映射关系。