SpringMVC 九大组件之 HandlerMapping 深入分析

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,接下来我们就对这三个关键类进行详细分析。

2.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

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值