SpringMVC核心组件之HandlerMapping详解


前言

当一个web请求到来时,DispatcherServlet负责接收请求并响应结果。DispatcherServlet首先需要找到当前请求对应的handler(处理器)来处理请求,流程如下图所示。
在这里插入图片描述

DispatcherServlet中有一个成员变量叫做handlerMappings,是一个HandlerMapping的集合,当请求到来时,DispatcherServlet遍历handlerMappings中的每一个HandlerMapping以获取对应的handler。上述步骤发生在DispatcherServlet的doDispatch() 方法中,部分源码如下所示。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    try {
        ModelAndView mv = null;
        Exception dispatchException = null;
        try {
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);
 
            // 根据请求获取handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // ......
        }
    }

}

handler的获取由DispatcherServlet的getHandler() 方法完成,下面再看一下getHandler() 具体做了什么事情。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

handlerMappings是HandlerMapping的集合,因此getHandler() 主要实现遍历每一个HandlerMapping并根据请求获取对应的handler。

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

  • handler 处理器可以将其理解成 HandlerMethod 对象(例如我们使用最多的 @RequestMapping 注解所标注的方法会解析成该对象),包含了方法的所有信息,通过该对象能够执行该方法
  • HandlerInterceptor 拦截器对处理请求进行增强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理 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 的继承关系如下:
在这里插入图片描述
在HandlerMapping类的层级结构图中,MatchableHandlerMapping接口是一个从Spring4.3.1开始新增的一个接口,用来判断给定的请求是否符合请求条件。
除此之外,HandlerMapping接口有一个公共的抽象类AbstractHandlerMapping,所有子孙实现类都需要继承。
该抽象类下有三个直接子类,分别是AbstractHandlerMethodMapping、AbstractUrlHandlerMapping和RouterFunctionMapping
其中RouterFunctionMapping是从Spring MVC5.2开始引入的,主要用于WebFlux处理中;
而另外两个直接实现类,代表了两大类实现方式:

  • AbstractUrlHandlerMapping表示根据url获取对应的handler;
  • AbstractHandlerMethodMapping表示基于方法的映射方式,这也是我们在实际工作中使用较多的一种方式。

一、AbstractHandlerMapping抽象类

AbstractHandlerMapping类图如下:
在这里插入图片描述
AbstractHandlerMapping,实现 HandlerMapping、Ordered、BeanNameAware 接口,继承 WebApplicationObjectSupport 抽象类,实现了“为请求找到合适的 HandlerExecutionChain 处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。

initApplicationContext

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

getHandler

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

@Override
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;
}

二、MatchableHandlerMapping类

MatchableHandlerMapping,定义了“判断请求和指定 pattern 路径是否匹配”的方法。

public interface MatchableHandlerMapping extends HandlerMapping {
    //返回{@code HandlerMapping}的解析器,如果配置了,则使用预先解析的模式。
	default PathPatternParser getPatternParser() {
		return null;
	}
	RequestMatchResult match(HttpServletRequest request, String pattern);

}

RequestMatchResult 类,判断请求和指定 pattern 路径是否匹配时,返回的匹配结果。

二、AbstractUrlHandlerMapping类

AbstractUrlHandlerMapping 主要用来通过URL进行匹配。思路如下:把URL与Handler的对应关系存到一个Map中,然后在getHandlerInternal方法中,根据URL去获取对应的Handler对象,在AbstractUrlHandlerMapping抽象类中,主要实现了根据url获取对应Handler的方法,如何初始化这个Map对象,交由子类进行实现。

主要属性

//根处理器,处理“/”的处理器
@Nullable
private Object rootHandler;
//是否匹配尾部的“/”,比如:如果设置为ture,则"/users"的匹配模式,也会匹配"/users/"
private boolean useTrailingSlashMatch = false;
//设置是否延迟加载,只对单例的处理器有效
private boolean lazyInitHandlers = false;
//保存request和Handler对应关系的变量
private final Map<String, Object> handlerMap = new LinkedHashMap<>();

getHandlerInternal方法
实现了父类中的抽象方法,根据request获取对应的handler

@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
	//获取lookupPath,并保存到request属性中
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	request.setAttribute(LOOKUP_PATH, lookupPath);
	//获取lookupPath 对应的handler
	Object handler = lookupHandler(lookupPath, request);
	if (handler == null) {//如果没有获取到对应的handler,则进行下面处理
		// We need to care for the default handler directly, since we need to
		// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
		Object rawHandler = null;
		if ("/".equals(lookupPath)) {//如果时根路径,则获取根处理器,即属性rootHandler中保存的处理器
			rawHandler = getRootHandler();
		}
		if (rawHandler == null) {//获取默认处理器,在父类中定义,即父类中的defaultHandler属性
			rawHandler = getDefaultHandler();
		}
		if (rawHandler != null) {
			// Bean name or resolved handler?
			if (rawHandler instanceof String) {//获取对应的Bean实例
				String handlerName = (String) rawHandler;
				rawHandler = obtainApplicationContext().getBean(handlerName);
			}
			//模板方法,校验处理器,交由子类实现或扩展
			validateHandler(rawHandler, request);
			//根据原始的handler构建实际的handler,主要实现构建HandlerExecutionChain对象,并在request添加对应的参数,后续在详细分析
			handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
		}
	}
	return handler;
}

相关推荐

  1. 10个SpringMVC核心组件详解

    2024-05-16 14:46:11       33 阅读
  2. Milvus核心组件(2)---- etcd 详解

    2024-05-16 14:46:11       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-16 14:46:11       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-16 14:46:11       101 阅读
  3. 在Django里面运行非项目文件

    2024-05-16 14:46:11       82 阅读
  4. Python语言-面向对象

    2024-05-16 14:46:11       91 阅读

热门阅读

  1. Mysql 多表查询

    2024-05-16 14:46:11       28 阅读
  2. python 合并 pdf

    2024-05-16 14:46:11       33 阅读
  3. Linux上diff命令

    2024-05-16 14:46:11       28 阅读
  4. gin之中间件消息转发使用踩坑记录

    2024-05-16 14:46:11       29 阅读
  5. 【Flutter 面试题】 讲一下 Dart 中 ?? 与 ??= 的区别

    2024-05-16 14:46:11       35 阅读
  6. oracle 临时表

    2024-05-16 14:46:11       27 阅读
  7. Redis教程(七):Redis中Set类型的常用命令

    2024-05-16 14:46:11       30 阅读
  8. Linux中的nproc命令

    2024-05-16 14:46:11       30 阅读
  9. 分层解耦-三层架构

    2024-05-16 14:46:11       33 阅读
  10. 外挂知识库的论文总结(后续还会更新)

    2024-05-16 14:46:11       36 阅读