SpringMVC之源码分析--HandlerMapping(五)

猫耳山在天边 2019-06-27

概述

通过前三章的分析,我们简要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但对拦截器部分做详细的分析,拦截器的加载和初始化是三个HandlerMapping相同的部分。本节补充下这块内容。

本系列文章是基于Spring5.0.5RELEASE。

类图

类的继承关系,如下图:

SpringMVC之源码分析--HandlerMapping(五)

我们知道Spring MVC将请求发送到Handler(Controller)处理器的功能是通过HandlerMapping组件完成的,HandlerMapping组件除了能找到Handler,还对拦截器进行了处理,具体实现是通过AbstractHandlerMapping抽象类完成的。

源码分析

  • HandlerMapping

HandlerMapping接口只定义了一个方法getHandler,其作用是返回请求的处理链HandlerExecutionChain,该对象封装了请求的拦截器以及请求处理Handler,方法定义如下:

@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
  • AbstractHandlerMapping

类声明源码如下:

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
    // ... ...
}

从类的定义可知道,AbstractHandlerMapping抽象类继承WebApplicationObjectSupport并实现了HandlerMapping和Ordered接口,其中:

  • 继承WebApplicationObjectSupport类提供了上下文ApplicationContext和ServletContext
  • 实现HandlerMapping接口为我们提供查找handler处理器功能
  • 实现Ordered接口,以提供排序能力,比如系统中使用多个HandlerMapping,可以定义每个HandlerMapping的顺序

简言之,AbstractHandlerMapping类为我们提供上下文环境、初始化拦截器并封装到HandlerExecutionChain对象中。

该类的入口方法,源代码如下:

/**
 * 初始化拦截器
 */
@Override
protected void initApplicationContext() throws BeansException {
    // 提供给子类去重写的,不过Spring并未去实现
    extendInterceptors(this.interceptors);
    // 加载拦截器
    detectMappedInterceptors(this.adaptedInterceptors);
    // 归并拦截器
    initInterceptors();
}

/**
 * 空实现
 */
protected void extendInterceptors(List<Object> interceptors) {
}

/**
 * 从上下文中加载MappedInterceptor类型的拦截器,比如我们在配置文件中使用
 * <mvc:interceptors></mvc:interceptors>
 * 标签配置的拦截器
 */
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
    mappedInterceptors.addAll(
            BeanFactoryUtils.beansOfTypeIncludingAncestors(
                    obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}

/**
 * 合并拦截器,即将<mvc:interceptors></mvc:interceptors>中的拦截器与HandlerMapping中通过属性interceptors设置的拦截器进行合并
 */
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");
            }
            // 适配后加入adaptedInterceptors
            this.adaptedInterceptors.add(adaptInterceptor(interceptor));
        }
    }
}

/**
 * 适配HandlerInterceptor和WebRequestInterceptor
 */
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
    if (interceptor instanceof HandlerInterceptor) {
        return (HandlerInterceptor) interceptor;
    }
    else if (interceptor instanceof WebRequestInterceptor) {
        return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
    }
    else {
        throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
    }
}

至此,拦截器初始化完成,接下来我们分析getHandler方法,源码如下:

/**
 * 返回请求处理的HandlerExecutionChain
 */
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // getHandlerInternal()为抽象方法,具体需子类实现
    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);
    }
    
    // 将请求处理器封装为HandlerExectionChain
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    // 对跨域的处理
    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    return executionChain;
}

/**
 * 钩子函数,需子类实现
 */
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

/**
 * 构建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) {
        // 如果拦截器是MappedInterceptor,判断是否对该handler进行拦截,是的情况下添加
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else { // HandlerInterceptor直接添加,即通过HandingMapping属性配置的拦截器
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

总结

本节我们补充了拦截器的加载初始化过程以及getHandler方法的实现分析,希望对大家有所帮助。

最后创建了qq群方便大家交流,可扫描加入,同时也可加我qq:276420284,共同学习、共同进步,谢谢!

SpringMVC之源码分析--HandlerMapping(五)

相关推荐