该系列文档是本人在学习 Spring MVC 的源码过程当中总结下来的,可能对读者不太友好,请结合个人源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读html
Spring 版本:5.2.4.RELEASEjava
该系列其余文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》git
HandlerMapping 组件,请求的处理器匹配器,负责为请求找到合适的 HandlerExecutionChain
处理器执行链,包含处理器(handler
)和拦截器们(interceptors
)github
handler
处理器是 Object 类型,能够将其理解成 HandlerMethod 对象(例如咱们使用最多的 @RequestMapping
注解所标注的方法会解析成该对象),包含了方法的全部信息,经过该对象可以执行该方法web
HandlerInterceptor
拦截器对处理请求进行加强处理,可用于在执行方法前、成功执行方法后、处理完成后进行一些逻辑处理spring
因为 HandlerMapping 组件涉及到的内容比较多,考虑到内容的排版,因此将这部份内容拆分红了四个模块,依次进行分析:数组
先来回顾一下在 DispatcherServlet
中处理请求的过程当中哪里使用到 HandlerMapping
组件,能够回到《一个请求的旅行过程》中的 DispatcherServlet
的 doDispatch
方法中看看,以下: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
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 的子类,分红两派,分别是:
@RequestMapping
等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,仍是使用这种方式。@RequestMapping
等注解的方式。绿色框的 MatchableHandlerMapping 接口,定义了“判断请求和指定 pattern
路径是否匹配”的方法。
在 DispatcherServlet
的 initHandlerMappings(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"); } } }
若是“开启”探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings
中,默认开启
若是“关闭”探测功能,则得到 Bean 名称为 "handlerMapping" 对应的 Bean ,将其添加至 handlerMappings
若是未得到到,则得到默认配置的 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 对象
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()
方法,用于初始化拦截器们,方法以下:
在父类 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(); }
调用 extendInterceptors(List<Object> interceptors)
方法,空方法,目前暂无子类实现,暂时忽略
调用 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()); }
调用 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(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; }
调用getHandlerInternal(HttpServletRequest request)
抽象方法,得到 handler
处理器
若是 handler
处理器没有找到,则调用getDefaultHandler()
方法,使用默认处理器,也就是 defaultHandler
属性
若是 handler
处理器没有找到,且没有默认的处理器,则直接返回 null
若是找到的处理器是 String 类型,多是 Bean 的名称,则从 Spring 容器中找到对应的 Bean 做为处理器
调用 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 }
handler
处理器就是该类型对象,则直接使用adaptedInterceptors
拦截器数组,根据请求路径得到当前请求匹配的拦截器们,添加到 HandlerExecutionChain 对象中返回上面建立的 HandlerExecutionChain 对象
org.springframework.web.servlet.handler.MatchableHandlerMapping
,定义了“判断请求和指定 pattern
路径是否匹配”的方法。代码以下:
public interface MatchableHandlerMapping extends HandlerMapping { /** * 判断请求和指定 pattern 路径是否匹配 */ @Nullable RequestMatchResult match(HttpServletRequest request, String pattern); }
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 组件的实现类分为两种:
@RequestMapping
等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,仍是使用这种方式@RequestMapping
等注解的方式AbstractHandlerMapping 抽象类,做为一个基类,实现了“为请求找到合适的 HandlerExecutionChain
处理器执行链”对应的的骨架逻辑,而暴露 getHandlerInternal(HttpServletRequest request)
抽象方法,交由子类实现。
本文对 HandlerMapping 组件作了一个简单的介绍,更多的细节交由其子类去实现,因为涉及到的内容比较多,BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping 两种实现类则在后续的文档中依次进行分析
参考文章:芋道源码《精尽 Spring MVC 源码分析》