HandlerMapping
HandlerMapping是request与handler object之间的映射,它能根据request找到对应的handler。handler object总会被包装成HandlerExecutionChain ,HandlerExecutionChain 里含有handler object、interceptor等。
HandlerMapping接口仅有一个方法getHandler,从方法注释中得知,handler object可以是任意类型,甚至都不需要实现标签接口,这样的好处是允许使用其他框架的handler object。
注意,在getHandler时,会进行content-type、参数、url、method等要素匹配,如果找不到对应的handler object(通常是@controller、@requestmapping注解的方法,也就是HandlerMethod),则会出抛出异常,返回404、405之类的状态码。
/**
* Return a handler and any interceptors for this request. The choice may be made
* on request URL, session state, or any factor the implementing class chooses.
* <p>The returned HandlerExecutionChain contains a handler Object, rather than
* even a tag interface, so that handlers are not constrained in any way.
* For example, a HandlerAdapter could be written to allow another framework's
* handler objects to be used.
* <p>Returns {@code null} if no match was found. This is not an error.
* The DispatcherServlet will query all registered HandlerMapping beans to find
* a match, and only decide there is an error if none can find a handler.
* @param request current HTTP request
* @return a HandlerExecutionChain instance containing handler object and
* any interceptors, or {@code null} if no mapping found
* @throws Exception if there is an internal error
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
看一个HandlerMapping实例,<mvc:annotation-driven>
标签注册RequestMappingHandlerMapping,它实现了HandlerMapping接口,此类中的lookupHandlerMethod方法负责寻找request对应的HandlerMethod。
/**
* Look up the best-matching handler method for the current request.
* If multiple matches are found, the best match is selected.
* @param lookupPath mapping lookup path within the current servlet mapping
* @param request the current request
* @return the best-matching handler method, or {@code null} if no match
* @see #handleMatch(Object, String, HttpServletRequest)
* @see #handleNoMatch(Set, String, HttpServletRequest)
*/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
// 省略
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
HandlerExecutionChain
HandlerExecutionChain 是Handler执行链,包含handler Object、interceptor。所以HandlerExecutionChain 提供了getHandler、getInterceptors方法,配置文件中配置的interceptor都会加入到HandlerExecutionChain
实例
接下来看一下HandlerMapping、HandlerExecutionChain的实际应用,DispatcherServlet的doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
大体流程是,根据request获取到HandlerExecutionChain ,根据HandlerExecutionChain 获取到handler,根据handler获取HandlerAdapter ,HandlerAdapter 判断文件是否被修改过,如果没修改过,直接返回。否则,HandlerExecutionChain 执行拦截器的prehandle方法,然后HandlerAdapter 执行实际处理。
HandlerAdapter
HandlerAdapter 是Handler适配器,负责具体的request处理,比如参数解析、返回值处理。
/**
* Use the given handler to handle this request.
* The workflow that is required may vary widely.
* @param request current HTTP request
* @param response current HTTP response
* @param handler handler to use. This object must have previously been passed
* to the {@code supports} method of this interface, which must have
* returned {@code true}.
* @throws Exception in case of errors
* @return ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
总结
个人感觉,HandlerMapping、HandlerExecutionChain 、HandlerAdapter是spring mvc最重要的三个组件了
- HandlerMapping
- 是request与handler object的映射,负责url、参数、content-type、method等匹配
- HandlerExecutionChain
- 是handler执行链,它包装了handler obejct、interceptor,很典型的包装对象
- HandlerAdapter
- 顾名思义,是handler的适配器,它能处理参数转换为handler能接受的数据类型,解析参数、处理返回值等