<spring.version>5.2.4.RELEASE</spring.version>
文章目录
- 1. 类关系依赖图与继承关系
- 2. AbstractHandlerMapping
- 2.1 初始化
- 2.2 使用
- 3. AbstractUrlHandlerMapping
- todo
1. 类关系依赖图与继承关系
主要看红线的,即如下继承关系:
2. AbstractHandlerMapping
还是见了很多次的模板模式,AbstractHandlerMapping设计了HandlerMapping实现的整体结构,子类只需要通过模板方法提供一些初始值或者具体的实现。
HandlerMapping的作用是根据request查找Handler和Interceptors。获取Handler的过程通过模板方法getHandlerInternal交给了子类。AbstractHandlerMapping中保存了所用配置的Interceptor,在获取到Handler后会自己根据从request提取的lookupPath将相应的Inte-rceptors装配上去,当然子类也可以通过getHandlerInternal方法设置自己的Interceptor,getHandlerInternal的返回值为Object类型。
2.1 初始化
AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化时会自动调用模板方法initApplicationContext,AbstractHandlerMapping的创建就是在initApplicationContext方法里面实现的。
@Overrideprotected void initApplicationContext() throws BeansException { //钩子函数留给子类实现,将子类添加的拦截器加入到interceptorsextendInterceptors(this.interceptors);//detectMappedInterceptors方法用于将Spring MVC容器及父容器中的所有MappedInter-ceptor类型的Bean添加到adaptedInterceptors属性detectMappedInterceptors(this.adaptedInterceptors);//initInterceptors方法的作用是初始化Interceptor,具体内容其实是将interceptors属性里所包含的对象按类型添加到adaptedInterceptorsinitInterceptors();}/ * **子类可以覆盖的扩展钩子来注册额外的拦截器,*给定配置的拦截器(参见{@link #setInterceptors})。**将在{@link #initInterceptors()}调整指定的代码之前被调用*拦截器到{@link HandlerInterceptor}实例。*默认实现为空。* @param拦截器配置的拦截器列表(从不{@code null}),允许*在现有的拦截器之前和之后添加更多的拦截器
* /protected void extendInterceptors(List<Object> interceptors) {}/ * **检测类型为{@link MappedInterceptor}的bean,并将其添加到映射的拦截器列表中。*这是在任何{@link MappedInterceptor MappedInterceptors}之外被调用的,可能已经提供*通过{@link #setInterceptors},默认情况下添加所有类型为{@link MappedInterceptor}的bean*从当前上下文及其祖先。子类可以重写和改进这个策略。添加{@link MappedInterceptor}实例到的空列表
* /protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {mappedInterceptors.addAll(BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), MappedInterceptor.class, true, false).values());}/ * **初始化指定的拦截器,检查{@link MappedInterceptor}和*适应{@link HandlerInterceptor}和{@link WebRequestInterceptor HandlerInterceptor}和* {@link WebRequestInterceptor}如果需要的话。* @see # setInterceptors* @see # adaptInterceptor* /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");}this.adaptedInterceptors.add(adaptInterceptor(interceptor));}}}
5.x 没有mappedInterceptors
mappedInterceptors:此类Interceptor在使用时需要与请求的url进行匹配,只有匹配成功后才会添加到getHandler的返回值HandlerExecutionChain里。它有两种获取途径:从interceptors获取或者注册到spring的容器中通过detectMappedInterceptors方法获取。
AbstractHandlerMapping中的Interceptor有三个List类型的属性:interceptors、adaptedInterceptors;
-
Interceptors:用于配置Spring MVC的拦截器,有两种设置方式:①注册Handler-Mapping时通过属性设置;②通过子类的extendInterceptors钩子方法进行设置。Interceptors并不会直接使用,而是通过initInterceptors方法按类型分配到adaptedInterceptors中进行使用,Interceptors只用于配置。
-
adaptedInterceptors:这种类型的Interceptor不需要进行匹配,在getHandler中会全部添加到返回值HandlerExecutionChain里面。它只能从interceptors中获取。
2.2 使用
HandlerMapping是通过getHandler方法来获取处理器Handler和拦截器Interceptor的。
/ * **查找给定请求的处理程序,返回到默认值*处理程序,如果没有找到特定的。* @param请求当前HTTP请求返回对应的处理程序实例,或默认处理程序* @see # getHandlerInternal* /@Override@Nullablepublic final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {//又是一个模板方法,获取HandlerObject handler = getHandlerInternal(request);if (handler == null) {//如果没有就使用默认的Handler//默认的Handler保存在AbstractHandler-Mapping的一个Object类型的属性defaultHandler中handler = getDefaultHandler();}if (handler == null) {return null;}// Bean名称还是解析处理程序?if (handler instanceof String) {String handlerName = (String) handler;//如果找到的Handler是String类型,则以它为名到Spring MVC的容器里查找相应的Bean。handler = obtainApplicationContext().getBean(handlerName);}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;}/***查找给定请求的处理程序,如果没有,返回{@code null}*找到了特定的一个。该方法由{@link #getHandler}调用;*一个{@code null}返回值将导致默认处理程序,如果设置了一个。对于CORS飞行前请求,此方法应该返回一个不匹配的*飞行前的请求,但基于URL的预期实际请求*路径,从“访问-控制-请求-方法”头的HTTP方法,和*来自“访问-控制-请求-报头”的报头因此允许* CORS配置通过{@link #getCorsConfiguration(Object, HttpServletRequest)}获得,注意:此方法也可能返回预先构建的{@link HandlerExecutionChain},*将处理程序对象与动态确定的拦截程序相结合。*静态指定的拦截器将合并到这样一个已有的链中。* @param请求当前HTTP请求* @返回相应的处理程序实例,如果没有找到,则返回{@code null}* @抛出异常,如果有内部错误*/@Nullableprotected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
接下来看:
/***为给定的处理程序构建{@link HandlerExecutionChain},包括*适用的拦截器。默认实现构建一个标准的{@link HandlerExecutionChain}*与给定的处理程序,处理程序映射的常见拦截器,和任何匹配当前请求URL。拦截器*按注册顺序添加。子类可以覆盖它*为了扩展/重新排列拦截器列表。注意:传递进来的处理程序对象可以是原始处理程序或a*预构建的{@link HandlerExecutionChain}。这个方法应该处理这些*显式地使用两种情况,要么构建一个新的{@link HandlerExecutionChain}*或扩展现有的链。如果只是在自定义子类中添加拦截器,请考虑调用* {@code超级。getHandlerExecutionChain(处理器,请求)}和调用在返回的链对象上* {@link HandlerExecutionChain#addInterceptor}。解析的处理程序实例(never {@code null})* @param请求当前HTTP请求* @return HandlerExecutionChain (never {@code null})* @see # getAdaptedInterceptors ()*/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) {//找到匹配的interceptor if (interceptor instanceof MappedInterceptor) {MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;//等于找到对应该路径的拦截器if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {chain.addInterceptor(mappedInterceptor.getInterceptor());}}else {//否则就是全局拦截器,加入执行链chain.addInterceptor(interceptor);}}return chain;}
再来看看MappedInterceptor 是个什么东西:
/* *包含并委托对{@link HandlerInterceptor}的调用 *包括(可选排除)拦截器应该应用的路径模式。 *还提供了匹配逻辑来测试拦截器是否适用于给定的请求路径。 MappedInterceptor可以直接注册到any * {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping}。 *此外,类型为{@code MappedInterceptor}的bean被自动检测 * {@code AbstractHandlerMethodMapping}(包括祖先ApplicationContext的) *有效地意味着拦截器注册为“全局”的所有处理程序映射。 */
public final class MappedInterceptor implements HandlerInterceptor {
看注释可见,这是一个特定的拦截器。
3. AbstractUrlHandlerMapping
从名字就可以看出它是通过url来进行匹配的。此系列大致原理是将url与对应的Handler保存在一个Map中,在getHandlerInternal方法中使用url从Map中获取Handler,AbstractUrlHandlerMapping中实现了具体用url从Map中获取Handler的过程,而Map的初始化则交给了具体的子孙类去完成。