精尽Spring MVC源码分析 - HandlerMapping 组件(一)之 AbstractHandlerMapping

该系列文档是本人在学习 Spring MVC 的源码过程当中总结下来的,可能对读者不太友好,请结合个人源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读html

Spring 版本:5.2.4.RELEASEjava

该系列其余文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》git

HandlerMapping 组件

HandlerMapping 组件,请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptorsgithub

  • handler 处理器是 Object 类型,能够将其理解成 HandlerMethod 对象(例如咱们使用最多的 @RequestMapping 注解所标注的方法会解析成该对象),包含了方法的全部信息,经过该对象可以执行该方法web

  • HandlerInterceptor 拦截器对处理请求进行加强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理spring

因为 HandlerMapping 组件涉及到的内容比较多,考虑到内容的排版,因此将这部份内容拆分红了四个模块,依次进行分析:数组

HandlerMapping 组件(一)之 AbstractHandlerMapping

先来回顾一下在 DispatcherServlet 中处理请求的过程当中哪里使用到 HandlerMapping 组件,能够回到《一个请求的旅行过程》中的 DispatcherServletdoDispatch 方法中看看,以下:mvc

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    // ... 省略相关代码
    // Determine handler for the current request.
    // <3> 得到请求对应的 HandlerExecutionChain 对象(HandlerMethod 和 HandlerInterceptor 拦截器们)
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) { // <3.1> 若是获取不到,则根据配置抛出异常或返回 404 错误
        noHandlerFound(processedRequest, response);
        return;
    }
    // ... 省略相关代码
}

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历 handlerMappings 组件们
        for (HandlerMapping mapping : this.handlerMappings) {
            // 经过 HandlerMapping 组件获取到 HandlerExecutionChain 对象
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                // 不为空则直接返回
                return handler;
            }
        }
    }
    return null;
}

经过遍历 HandlerMapping 组件们,根据请求获取到对应 HandlerExecutionChain 处理器执行链。注意,这里是经过一个一个的 HandlerMapping 组件去进行处理,若是找到对应 HandlerExecutionChain 对象则直接返回,不会继续下去,因此初始化的 HandlerMapping 组件是有必定的前后顺序的,默认是BeanNameUrlHandlerMapping -> RequestMappingHandlerMappingapp

HandlerMapping 接口

org.springframework.web.servlet.HandlerMapping 接口,请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors),代码以下:cors

public interface HandlerMapping {

	String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";

	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";

	/**
	 * 得到请求对应的处理器和拦截器们
	 */
	@Nullable
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

类图

HandlerMapping 接口体系的结构以下:

  • 蓝色框 AbstractHandlerMapping 抽象类,实现了“为请求找到合适的 HandlerExecutionChain 处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。

  • AbstractHandlerMapping 的子类,分红两派,分别是:

    • 黄色框 AbstractUrlHandlerMapping 系,基于 URL 进行匹配。例如 《基于 XML 配置的 Spring MVC 简单的 HelloWorld 实例应用》 ,固然,目前这种方式已经基本不用了,被 @RequestMapping 等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,仍是使用这种方式。
    • 红色框 AbstractHandlerMethodMapping 系,基于 Method 进行匹配。例如,咱们所熟知的 @RequestMapping 等注解的方式。
  • 绿色框的 MatchableHandlerMapping 接口,定义了“判断请求和指定 pattern 路径是否匹配”的方法。

初始化过程

DispatcherServletinitHandlerMappings(ApplicationContext context) 方法,会在 onRefresh 方法被调用,初始化 HandlerMapping 组件,方法以下:

private void initHandlerMappings(ApplicationContext context) {
    // 置空 handlerMappings
    this.handlerMappings = null;

    // <1> 若是开启探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings 中
    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        // 扫描已注册的 HandlerMapping 的 Bean 们
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context,
                HandlerMapping.class, true, false);
        // 添加到 handlerMappings 中,并进行排序
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    // <2> 若是关闭探测功能,则得到 Bean 名称为 "handlerMapping" 对应的 Bean ,将其添加至 handlerMappings
    else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }
    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    /**
     * <3> 若是未得到到,则得到默认配置的 HandlerMapping 类
     * {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}
     * {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping}
     */
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
  1. 若是“开启”探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings 中,默认开启

  2. 若是“关闭”探测功能,则得到 Bean 名称为 "handlerMapping" 对应的 Bean ,将其添加至 handlerMappings

  3. 若是未得到到,则得到默认配置的 HandlerMapping 类,调用 getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) 方法,就是从 DispatcherServlet.properties 文件中读取 HandlerMapping 的默认实现类,以下:

    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

    能够看到对应的是 BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping 对象

AbstractHandlerMapping

org.springframework.web.servlet.handler.AbstractHandlerMapping,实现 HandlerMapping、Ordered、BeanNameAware 接口,继承 WebApplicationObjectSupport 抽象类

该类是 HandlerMapping 接口的抽象基类,实现了“为请求找到合适的 HandlerExecutionChain 处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现

WebApplicationObjectSupport 抽象类,提供 applicationContext 属性的声明和注入。

构造方法

public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware {

	/**
	 * 默认处理器
	 */
	@Nullable
	private Object defaultHandler;

	/**
	 * URL 路径工具类
	 */
	private UrlPathHelper urlPathHelper = new UrlPathHelper();

	/**
	 * 路径匹配器
	 */
	private PathMatcher pathMatcher = new AntPathMatcher();

	/**
	 * 配置的拦截器数组.
	 *
	 * 在 {@link #initInterceptors()} 方法中,初始化到 {@link #adaptedInterceptors} 中
	 *
	 * 添加方式有两种:
	 * 1. {@link #setInterceptors(Object...)} 方法
	 * 2. {@link #extendInterceptors(List)} 方法
	 */
	private final List<Object> interceptors = new ArrayList<>();

	/**
	 * 初始化后的拦截器 HandlerInterceptor 数组
	 */
	private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

	private CorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();

	private CorsProcessor corsProcessor = new DefaultCorsProcessor();

	private int order = Ordered.LOWEST_PRECEDENCE;  // default: same as non-Ordered

	/**
	 * 当前 Bean 的名称
	 */
	@Nullable
	private String beanName;
    
    // ... 省略相关 getter、setter 方法
}
  • defaultHandler默认处理器,在得到不处处理器时,可以使用该属性

  • interceptors配置的拦截器数组

  • adaptedInterceptors初始化后的拦截器 HandlerInterceptor 数组,也就是interceptors 转换成的 HandlerInterceptor 拦截器对象

initApplicationContext

initApplicationContext()方法,用于初始化拦截器们,方法以下:

在父类 WebApplicationObjectSupport 的父类 ApplicationObjectSupport 中能够看到,由于实现了 ApplicationContextAware 接口,则在初始化该 Bean 的时候会调用 setApplicationContext(@Nullable ApplicationContext context) 方法,在这个方法中会调用 initApplicationContext() 这个方法

@Override
protected void initApplicationContext() throws BeansException {
    // <1> 空实现,交给子类实现,用于注册自定义的拦截器到 interceptors 中,目前暂无子类实现
    extendInterceptors(this.interceptors);
    // <2> 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
    detectMappedInterceptors(this.adaptedInterceptors);
    // <3> 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
    initInterceptors();
}
  1. 调用 extendInterceptors(List<Object> interceptors) 方法,空方法,目前暂无子类实现,暂时忽略

  2. 调用 detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) 方法,从 Spring 的上下文中,扫描已注册的 MappedInterceptor 的拦截器们,添加到 adaptedInterceptors 中,方法以下:

    protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
        // 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
        // MappedInterceptor 会根据请求路径作匹配,是否进行拦截
        mappedInterceptors.addAll(BeanFactoryUtils
                .beansOfTypeIncludingAncestors(obtainApplicationContext(), MappedInterceptor.class, true, false)
                .values());
    }
  3. 调用 initInterceptors() 方法,将 interceptors 初始化成 HandlerInterceptor 类型,添加到 adaptedInterceptors 中,方法以下:

    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");
                }
                // 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
                // 注意,HandlerInterceptor 无需进行路径匹配,直接拦截所有
                this.adaptedInterceptors.add(adaptInterceptor(interceptor));
            }
        }
    }
    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

getHandler(HttpServletRequest request) 方法,得到请求对应的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors),方法以下:

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // <1> 得到处理器(HandlerMethod 或者 HandlerExecutionChain),该方法是抽象方法,由子类实现
    Object handler = getHandlerInternal(request);
    // <2> 得到不到,则使用默认处理器
    if (handler == null) {
        handler = getDefaultHandler();
    }
    // <3> 仍是得到不到,则返回 null
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    // <4> 若是找到的处理器是 String 类型,则从 Spring 容器中找到对应的 Bean 做为处理器
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // <5> 建立 HandlerExecutionChain 对象(包含处理器和拦截器)
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}
  1. 调用getHandlerInternal(HttpServletRequest request) 抽象方法,得到 handler 处理器

  2. 若是 handler 处理器没有找到,则调用getDefaultHandler() 方法,使用默认处理器,也就是 defaultHandler 属性

  3. 若是 handler 处理器没有找到,且没有默认的处理器,则直接返回 null

  4. 若是找到的处理器是 String 类型,多是 Bean 的名称,则从 Spring 容器中找到对应的 Bean 做为处理器

  5. 调用 getHandlerExecutionChain(Object handler, HttpServletRequest request) 方法,得到 HandlerExecutionChain 对象,方法以下:

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        // <1> 建立 HandlerExecutionChain 对象
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler
                : new HandlerExecutionChain(handler));
    
        // <2> 得到请求路径
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        // <3> 遍历 adaptedInterceptors 数组,得到请求匹配的拦截器
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            // 须要匹配,若路径匹配,则添加到 chain 中
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 匹配
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            // 无需匹配,直接添加到 chain 中
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain
    }
    1. 建立一个 HandlerExecutionChain 对象,若是 handler 处理器就是该类型对象,则直接使用
    2. 得到请求路径
    3. 遍历 adaptedInterceptors 拦截器数组,根据请求路径得到当前请求匹配的拦截器们,添加到 HandlerExecutionChain 对象中
  6. 返回上面建立的 HandlerExecutionChain 对象

MatchableHandlerMapping

org.springframework.web.servlet.handler.MatchableHandlerMapping,定义了“判断请求和指定 pattern 路径是否匹配”的方法。代码以下:

public interface MatchableHandlerMapping extends HandlerMapping {

	/**
	 * 判断请求和指定 pattern 路径是否匹配
	 */
	@Nullable
	RequestMatchResult match(HttpServletRequest request, String pattern);
}

RequestMatchResult

org.springframework.web.servlet.handler.RequestMatchResult 类,判断请求和指定 pattern 路径是否匹配时,返回的匹配结果,代码以下:

public class RequestMatchResult {
	/**
	 * 匹配到的路径
	 */
	private final String matchingPattern;

	/**
	 * 被匹配的路径
	 */
	private final String lookupPath;

	/**
	 * 路径匹配器
	 */
	private final PathMatcher pathMatcher;

	public RequestMatchResult(String matchingPattern, String lookupPath, PathMatcher pathMatcher) {
		Assert.hasText(matchingPattern, "'matchingPattern' is required");
		Assert.hasText(lookupPath, "'lookupPath' is required");
		Assert.notNull(pathMatcher, "'pathMatcher' is required");
		this.matchingPattern = matchingPattern;
		this.lookupPath = lookupPath;
		this.pathMatcher = pathMatcher;
	}

	public Map<String, String> extractUriTemplateVariables() {
		return this.pathMatcher.extractUriTemplateVariables(this.matchingPattern, this.lookupPath);
	}
}

目前实现 MatchableHandlerMapping 接口的类,有 RequestMappingHandlerMapping 类和 AbstractUrlHandlerMapping 抽象类,在后续都会进行分析

总结

本文对 Spring MVC 处理请求的过程当中使用到的 HandlerMapping 组件进行了分析,会为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器们(interceptors

HandlerMapping 组件的实现类分为两种:

  • 基于 URL 进行匹配。例如 《基于 XML 配置的 Spring MVC 简单的 HelloWorld 实例应用》 ,固然,目前这种方式已经基本不用了,被 @RequestMapping 等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,仍是使用这种方式
  • 基于 Method 进行匹配。例如,咱们所熟知的 @RequestMapping 等注解的方式

AbstractHandlerMapping 抽象类,做为一个基类,实现了“为请求找到合适的 HandlerExecutionChain 处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。

本文对 HandlerMapping 组件作了一个简单的介绍,更多的细节交由其子类去实现,因为涉及到的内容比较多,BeanNameUrlHandlerMappingRequestMappingHandlerMapping 两种实现类则在后续的文档中依次进行分析

参考文章:芋道源码《精尽 Spring MVC 源码分析》

相关文章
相关标签/搜索