跳至主要內容

7.HandlerMapping 组件(一)之 AbstractHandlerMapping

Java突击队大约 10 分钟

7.HandlerMapping 组件(一)之 AbstractHandlerMapping

Spring 版本:5.1.14.RELEASE

该系列其他文档请查看:《死磕 Spring MVC 源码分析 - 文章导读》open in new window

HandlerMapping 组件

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

  • handler 处理器是 Object 类型,可以将其理解成 HandlerMethod 对象(例如我们使用最多的 @RequestMapping 注解所标注的方法会解析成该对象),包含了方法的所有信息,通过该对象能够执行该方法
  • HandlerInterceptor 拦截器对处理请求进行增强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理

由于HandlerMapping 组件涉及到的内容比较多,考虑到内容的排版,所以将这部分内容拆分成了四个模块,依次进行分析:

HandlerMapping 组件(一)之 AbstractHandlerMapping

先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 HandlerMapping 组件,可以回到《一个请求的旅行过程》open in new window中的 DispatcherServletdoDispatch 方法中看看,如下:

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 -> RequestMappingHandlerMapping

HandlerMapping 接口

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

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 实例应用》open in new window ,当然,目前这种方式已经基本不用了,被 @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(ApplicationContextcontext,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(HttpServletRequestrequest)抽象方法,获得handler处理器;
2、 如果handler处理器没有找到,则调用getDefaultHandler()方法,使用默认处理器,也就是defaultHandler属性;
3、 如果handler处理器没有找到,且没有默认的处理器,则直接返回null
4、 如果找到的处理器是String类型,可能是Bean的名称,则从Spring容器中找到对应的Bean作为处理器;
5、 调用getHandlerExecutionChain(Objecthandler,HttpServletRequestrequest)方法,获得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 组件的实现类分为两种:

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

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

参考文章:芋道源码《死磕 Spring MVC 源码分析》open in new window

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址:open in new window