HandlerMapping 叫做处理器映射器,它的作用就是根据当前 request 找到对应的 Handler 和 Interceptor,然后封装成一个 HandlerExecutionChain 对象返回,我们来看下 HandlerMapping 接口:
public interface HandlerMapping {
String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + “.bestMatchingHandler”;
@Deprecated
String LOOKUP_PATH = HandlerMapping.class.getName() + “.lookupPath”;
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + “.pathWithinHandlerMapping”;
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + “.bestMatchingPattern”;
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + “.introspectTypeLevelMapping”;
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + “.uriTemplateVariables”;
String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + “.matrixVariables”;
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + “.producibleMediaTypes”;
default boolean usesPathPatterns() {
return false;
}
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
可以看到,除了一堆声明的常量外,其实就一个需要实现的方法 getHandler,该方法的返回值就是我们所了解到的 HandlerExecutionChain。
HandlerMapping 的继承关系如下:
这个继承关系虽然看着有点绕,其实仔细观察就两大类:
-
AbstractHandlerMethodMapping
-
AbstractUrlHandlerMapping
其他的都是一些辅助接口。
AbstractHandlerMethodMapping 体系下的都是根据方法名进行匹配的,而 AbstractUrlHandlerMapping 体系下的都是根据 URL 路径进行匹配的,这两者有一个共同的父类 AbstractHandlerMapping,接下来我们就对这三个关键类进行详细分析。
AbstractHandlerMapping 实现了 HandlerMapping 接口,无论是通过 URL 进行匹配还是通过方法名进行匹配,都是通过继承 AbstractHandlerMapping 来实现的,所以 AbstractHandlerMapping 所做的事情其实就是一些公共的事情,将以一些需要具体处理的事情则交给子类去处理,这其实就是典型的模版方法模式。
AbstractHandlerMapping 间接继承自 ApplicationObjectSupport,并重写了 initApplicationContext 方法(其实该方法也是一个模版方法),这也是 AbstractHandlerMapping 的初始化入口方法,我们一起来看下:
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
三个方法都和拦截器有关。
extendInterceptors
protected void extendInterceptors(List interceptors) {
}
extendInterceptors 是一个模版方法,可以在子类中实现,子类实现了该方法之后,可以对拦截器进行添加、删除或者修改,不过在 SpringMVC 的具体实现中,其实这个方法并没有在子类中进行实现。
detectMappedInterceptors
protected void detectMappedInterceptors(List mappedInterceptors) {
mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
detectMappedInterceptors 方法会从 SpringMVC 容器以及 Spring 容器中查找所有 MappedInterceptor 类型的 Bean,查找到之后添加到 mappedInterceptors 属性中(其实就是全局的 adaptedInterceptors 属性)。一般来说,我们定义好一个拦截器之后,还要在 XML 文件中配置该拦截器,拦截器以及各种配置信息,最终就会被封装成一个 MappedInterceptor 对象。
initInterceptors
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException(“Entry number " + i + " in interceptors array is null”);
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
initInterceptors 方法主要是进行拦截器的初始化操作,具体内容是将 interceptors 集合中的拦截器添加到 adaptedInterceptors 集合中。
至此,我们看到,所有拦截器最终都会被存入 adaptedInterceptors 变量中。
AbstractHandlerMapping 的初始化其实也就是拦截器的初始化过程。
为什么 AbstractHandlerMapping 中对拦截器如此重视呢?其实不是重视,大家想想,AbstractUrlHandlerMapping 和 AbstractHandlerMethodMapping 最大的区别在于查找处理器的区别,一旦处理器找到了,再去找拦截器,但是拦截器都是统一的,并没有什么明显区别,所以拦截器就统一在 AbstractHandlerMapping 中进行处理,而不会去 AbstractUrlHandlerMapping 或者 AbstractHandlerMethodMapping 中处理。
接下来我们再来看看 AbstractHandlerMapping#getHandler 方法,看看处理器是如何获取到的:
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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 = obtainApplicationContext().getBean(handlerName);
}
// Ensure presence of cached lookupPath for interceptors and others
if (!ServletRequestPathUtils.hasCachedPath(request)) {
initLookupPath(request);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (hasCorsConfiguratio