目录
- 第一部分:启动阶段 —— 拦截器的配置、收集、包装与存储
- 第 1 章:`DelegatingWebMvcConfiguration` 的由来 —— 它是如何被 Spring 管理的?
- 1.1 纯 Spring MVC 项目:通过 `@EnableWebMvc` 的 `@Import` 机制
- 1.2 Spring Boot 项目:通过自动配置引入
- 1.3 `DelegatingWebMvcConfiguration` 的继承结构
- 第 2 章:`@Autowired` 收集所有 `WebMvcConfigurer`
- 第 3 章:`WebMvcConfigurationSupport` 中的 `@Bean` 定义 —— `RequestMappingHandlerMapping` 的创建
- 第 4 章:`getInterceptors()` 的内部执行流程
- 第 5 章:`registry.getInterceptors()` —— 生成 `MappedInterceptor[]` 数组
- 第 6 章:`RequestMappingHandlerMapping` 的 Bean 生命周期 —— `initInterceptors()` 的执行
- 第二部分:运行阶段 —— 请求到来时拦截器的匹配与执行
- 第 7 章:`DispatcherServlet.doDispatch()` —— 拦截器链的构建入口
- 第 8 章:`getHandlerExecutionChain()` —— 拦截器匹配逻辑
- 第 9 章:`MappedInterceptor.matches()` —— 路径匹配的核心算法
- 第 10 章:拦截器链的执行 —— `HandlerExecutionChain` 的三个调用点
- 第三部分:总结
- 第 11 章:完整时序图
- 第 12 章:核心设计思想
- 第 13 章:关键源码位置速查
第一部分:启动阶段 —— 拦截器的配置、收集、包装与存储
第 1 章:DelegatingWebMvcConfiguration的由来 —— 它是如何被 Spring 管理的?
DelegatingWebMvcConfiguration是 Spring MVC 中连接“核心配置”与“用户扩展”的总枢纽。它被 Spring 管理的方式有两种,取决于你的项目类型。
1.1 纯 Spring MVC 项目:通过@EnableWebMvc的@Import机制
在非 Spring Boot 项目中,你需要显式添加@EnableWebMvc注解。查看该注解的源码:
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(DelegatingWebMvcConfiguration.class)public@interfaceEnableWebMvc{}@Import(DelegatingWebMvcConfiguration.class)会直接将DelegatingWebMvcConfiguration注册为 Spring 容器的一个 Bean。这是 Spring 注解驱动的核心机制——@Import可以导入一个配置类,使其所有@Bean方法生效。
1.2 Spring Boot 项目:通过自动配置引入
在 Spring Boot 项目中,你无需手动加@EnableWebMvc。WebMvcAutoConfiguration是 Spring Boot 的 MVC 自动配置类,它内部通过@Import(EnableWebMvcConfiguration.class)引入了一个配置类,该类直接继承了DelegatingWebMvcConfiguration。由于WebMvcAutoConfiguration本身是自动配置类,被 Spring Boot 自动加载,因此DelegatingWebMvcConfiguration的子类也自然成为 Spring 容器中的 Bean。
1.3DelegatingWebMvcConfiguration的继承结构
DelegatingWebMvcConfiguration继承自WebMvcConfigurationSupport,后者提供了 Spring MVC 所有核心基础设施的@Bean定义(如RequestMappingHandlerMapping、HandlerAdapter、ViewResolver等)。DelegatingWebMvcConfiguration在其中扮演了“委托”的角色——它不直接实现配置逻辑,而是将所有配置调用转发给一个组合对象,而这个组合对象会收集所有WebMvcConfigurer的实现。
第 2 章:@Autowired收集所有WebMvcConfigurer
DelegatingWebMvcConfiguration中有一个关键方法:
@Autowired(required=false)publicvoidsetConfigurers(List<WebMvcConfigurer>configurers){if(!CollectionUtils.isEmpty(configurers)){this.configurers.addWebMvcConfigurers(configurers);}}@Autowired(required = false)告诉 Spring:如果有任何WebMvcConfigurer类型的 Bean,请全部注入到这里。List<WebMvcConfigurer>会包含你写的WebConfig类,以及任何第三方库(如 Spring Security)提供的配置类。- 这些配置被传递给
WebMvcConfigurerComposite的addWebMvcConfigurers方法,存入其内部的delegates列表。
WebMvcConfigurerComposite是一个组合模式的实现,它实现了WebMvcConfigurer接口,内部维护一个List<WebMvcConfigurer> delegates。后续所有配置方法被调用时,它都会遍历delegates,依次调用每个配置类的对应方法。这保证了多个配置类可以并存,且按照添加顺序依次生效。
第 3 章:WebMvcConfigurationSupport中的@Bean定义 ——RequestMappingHandlerMapping的创建
WebMvcConfigurationSupport中有一个关键的@Bean方法:
@BeanpublicRequestMappingHandlerMappingrequestMappingHandlerMapping(@Qualifier("mvcContentNegotiationManager")ContentNegotiationManagercontentNegotiationManager,@Qualifier("mvcConversionService")FormattingConversionServiceconversionService,@Qualifier("mvcResourceUrlProvider")ResourceUrlProviderresourceUrlProvider){RequestMappingHandlerMappingmapping=createRequestMappingHandlerMapping();mapping.setOrder(0);// 【核心】这一行触发了拦截器配置的收集和包装mapping.setInterceptors(getInterceptors(conversionService,resourceUrlProvider));mapping.setContentNegotiationManager(contentNegotiationManager);// ... 其他配置returnmapping;}mapping.setInterceptors(getInterceptors(...))是整条链路的触发点。它调用了getInterceptors()方法,这个方法会执行以下操作:
- 创建一个
InterceptorRegistry实例。 - 调用
addInterceptors(registry)(这是一个由子类DelegatingWebMvcConfiguration重写的方法)。 - 调用
registry.getInterceptors()将注册信息转换为Object[]数组,其中包含MappedInterceptor和普通拦截器。 - 将这个数组设置给
HandlerMapping实例。
第 4 章:getInterceptors()的内部执行流程
WebMvcConfigurationSupport.getInterceptors()的完整源码如下:
protectedfinalObject[]getInterceptors(FormattingConversionServicemvcConversionService,ResourceUrlProvidermvcResourceUrlProvider){if(this.interceptors==null){InterceptorRegistryregistry=newInterceptorRegistry();// 【多态调用】实际执行的是 DelegatingWebMvcConfiguration.addInterceptorsaddInterceptors(registry);// 【关键转换】将注册信息转换为 MappedInterceptor 数组this.interceptors=registry.getInterceptors();}returnthis.interceptors.toArray();}addInterceptors(registry)在父类WebMvcConfigurationSupport中是空实现,但DelegatingWebMvcConfiguration重写了它:
// DelegatingWebMvcConfiguration.java@OverrideprotectedvoidaddInterceptors(InterceptorRegistryregistry){this.configurers.addInterceptors(registry);}this.configurers是WebMvcConfigurerComposite实例,它的addInterceptors方法遍历delegates列表:
@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){for(WebMvcConfigurerdelegate:this.delegates){delegate.addInterceptors(registry);// 调用你自己写的 WebConfig.addInterceptors}}- 在你的
WebConfig中,你调用了registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/admin/**")。这一步将拦截器实例和路径规则存入InterceptorRegistry内部的InterceptorRegistration对象中。
第 5 章:registry.getInterceptors()—— 生成MappedInterceptor[]数组
InterceptorRegistry.getInterceptors()的源码:
publicObject[]getInterceptors(){List<Object>interceptors=newArrayList<>();for(InterceptorRegistrationregistration:this.registrations){interceptors.add(registration.getInterceptor());}returninterceptors.toArray();}InterceptorRegistration.getInterceptor()的核心逻辑:
protectedObjectgetInterceptor(){if(this.includePatterns.isEmpty()&&this.excludePatterns.isEmpty()){returnthis.interceptor;// 没有路径规则,直接返回原始拦截器}// 有路径规则,包装成 MappedInterceptorreturnnewMappedInterceptor(this.includePatterns,this.excludePatterns,this.interceptor);}MappedInterceptor是一个包装类,它同时持有拦截器实例和路径匹配规则(includePatterns和excludePatterns),用于运行时判断当前请求是否应该应用该拦截器。
最终,getInterceptors()返回的数组中包含了你配置的所有拦截器(无路径规则的为原始拦截器,有路径规则的为MappedInterceptor),并通过mapping.setInterceptors()设置给了RequestMappingHandlerMapping实例。
第 6 章:RequestMappingHandlerMapping的 Bean 生命周期 ——initInterceptors()的执行
RequestMappingHandlerMapping的继承链中存在关键接口:ApplicationContextAware。当一个 Bean 实现了ApplicationContextAware,Spring 容器在初始化该 Bean 时会回调其setApplicationContext方法。
AbstractHandlerMapping的父类ApplicationObjectSupport实现了ApplicationContextAware接口,并重写了setApplicationContext:
@OverridepublicfinalvoidsetApplicationContext(ApplicationContextcontext)throwsBeansException{// ...initApplicationContext();// 模板方法}AbstractHandlerMapping重写了initApplicationContext():
@OverrideprotectedvoidinitApplicationContext()throwsBeansException{extendInterceptors(this.interceptors);detectMappedInterceptors(this.adaptedInterceptors);initInterceptors();// 【最终执行】}initInterceptors()的源码:
protectedvoidinitInterceptors(){if(!ObjectUtils.isEmpty(this.interceptors)){for(Objectinterceptor:this.interceptors){if(interceptorinstanceofMappedInterceptor){// 带路径规则的,存入 mappedInterceptorsthis.mappedInterceptors.add((MappedInterceptor)interceptor);}else{// 普通拦截器,适配后存入 adaptedInterceptorsthis.adaptedInterceptors.add(adaptInterceptor(interceptor));}}}}interceptors数组是在第 3 章中通过setInterceptors设置进来的。- 分类后,
mappedInterceptors存放所有带路径规则的拦截器,adaptedInterceptors存放普通拦截器(对所有请求生效)。
至此,启动阶段结束。内存状态:AbstractHandlerMapping中已有mappedInterceptors和adaptedInterceptors两个集合,等待请求到来时被使用。
第二部分:运行阶段 —— 请求到来时拦截器的匹配与执行
第 7 章:DispatcherServlet.doDispatch()—— 拦截器链的构建入口
在doDispatch()中,首先调用getHandler(processedRequest)获取HandlerExecutionChain:
mappedHandler=getHandler(processedRequest);getHandler()遍历所有HandlerMapping,最终进入AbstractHandlerMapping.getHandler(),它内部调用getHandlerExecutionChain(handler, request)来构建执行链。
第 8 章:getHandlerExecutionChain()—— 拦截器匹配逻辑
protectedHandlerExecutionChaingetHandlerExecutionChain(Objecthandler,HttpServletRequestrequest){HandlerExecutionChainchain=(handlerinstanceofHandlerExecutionChain)?(HandlerExecutionChain)handler:newHandlerExecutionChain(handler);// 遍历 adaptedInterceptors:普通拦截器直接加入for(HandlerInterceptorinterceptor:this.adaptedInterceptors){chain.addInterceptor(interceptor);}// 遍历 mappedInterceptors:带路径规则的,需要匹配for(HandlerInterceptorinterceptor:this.mappedInterceptors){if(interceptorinstanceofMappedInterceptor){MappedInterceptormappedInterceptor=(MappedInterceptor)interceptor;if(mappedInterceptor.matches(request)){chain.addInterceptor(mappedInterceptor.getInterceptor());}}}returnchain;}- 首先,所有普通拦截器(无路径规则)无条件加入执行链。
- 然后,对每个
MappedInterceptor,调用matches(request)判断当前请求是否匹配其路径规则。若匹配,则将其内部的拦截器实例加入执行链。
第 9 章:MappedInterceptor.matches()—— 路径匹配的核心算法
publicbooleanmatches(HttpServletRequestrequest){// 1. 获取请求路径StringlookupPath=this.urlPathHelper.getLookupPathForRequest(request);// 2. 优先检查排除规则if(this.excludePatterns!=null){for(Stringpattern:this.excludePatterns){if(this.pathMatcher.match(pattern,lookupPath)){returnfalse;// 命中排除规则,不生效}}}// 3. 检查包含规则if(this.includePatterns==null){returntrue;// 没有包含规则,默认对所有请求生效}for(Stringpattern:this.includePatterns){if(this.pathMatcher.match(pattern,lookupPath)){returntrue;// 命中包含规则,生效}}returnfalse;// 没有命中任何包含规则,不生效}urlPathHelper.getLookupPathForRequest(request)获取请求路径(例如/admin/user)。excludePatterns优先判断:如果路径匹配任意排除规则,直接返回false。includePatterns判断:如果没有配置包含规则,默认匹配所有请求;否则必须匹配至少一个包含规则才返回true。pathMatcher默认是AntPathMatcher,支持*(单层)、**(多层)、?(单个字符)等通配符。
第 10 章:拦截器链的执行 ——HandlerExecutionChain的三个调用点
HandlerExecutionChain构建完成后,doDispatch在三个不同时机调用其方法。
10.1applyPreHandle()—— Controller 执行前
if(!mappedHandler.applyPreHandle(processedRequest,response)){return;// 任意拦截器返回 false,请求中断}applyPreHandle按正序执行所有拦截器的preHandle方法,一旦某个返回false,立即触发已执行拦截器的afterCompletion并返回false,后续代码不再执行。
10.2applyPostHandle()—— Controller 执行后,视图渲染前
mappedHandler.applyPostHandle(processedRequest,response,mv);逆序执行所有拦截器的postHandle方法。
10.3triggerAfterCompletion()—— 视图渲染后或异常时
mappedHandler.triggerAfterCompletion(processedRequest,response,null);在processDispatchResult的finally块中调用,逆序执行所有拦截器的afterCompletion,保证资源释放。
10.4interceptorIndex的作用
HandlerExecutionChain内部维护interceptorIndex,记录当前执行到哪个拦截器。当preHandle失败回滚时,只对interceptorIndex之前的拦截器执行afterCompletion,避免未初始化的拦截器被误调用。
第三部分:总结
第 11 章:完整时序图
启动阶段:
Spring 容器启动 ↓ DelegatingWebMvcConfiguration 被 Spring 管理(通过 @Import 或 Boot 自动配置) ↓ @Autowired setConfigurers(List<WebMvcConfigurer>) 收集所有 WebMvcConfigurer ↓ 存入 WebMvcConfigurerComposite.delegates ↓ WebMvcConfigurationSupport @Bean 创建 RequestMappingHandlerMapping ↓ mapping.setInterceptors(getInterceptors(...)) ↓ getInterceptors() 创建 InterceptorRegistry,调用 addInterceptors(registry) ↓ addInterceptors(registry) 多态 → DelegatingWebMvcConfiguration.addInterceptors ↓ WebMvcConfigurerComposite.addInterceptors → 遍历 delegates ↓ 你的 WebConfig.addInterceptors(registry) 执行 → 拦截器注册到 InterceptorRegistry ↓ registry.getInterceptors() → 生成 MappedInterceptor[] 数组 ↓ mapping.setInterceptors(interceptors) 存储到 AbstractHandlerMapping.interceptors ↓ Bean 初始化 → ApplicationContextAware.setApplicationContext 回调 ↓ AbstractHandlerMapping.initApplicationContext() → initInterceptors() ↓ 分类存储:MappedInterceptor → mappedInterceptors,普通 → adaptedInterceptors运行阶段:
请求到来 → DispatcherServlet.doDispatch() ↓ getHandler(processedRequest) → AbstractHandlerMapping.getHandler() ↓ getHandlerExecutionChain(handler, request) ├── adaptedInterceptors 全部加入 └── 遍历 mappedInterceptors ↓ MappedInterceptor.matches(request) 判断路径 ├── 匹配 excludePatterns → 跳过 ├── 未配置 includePatterns → 加入 └── 匹配 includePatterns → 加入 ↓ applyPreHandle() → 正序执行 preHandle,失败则中断并回滚 ↓ ha.handle() → 执行 Controller ↓ applyPostHandle() → 逆序执行 postHandle ↓ processDispatchResult() → 视图渲染 / JSON 输出 ↓ triggerAfterCompletion() → 逆序执行 afterCompletion第 12 章:核心设计思想
| 设计思想 | 体现 |
|---|---|
| 组合模式 | WebMvcConfigurerComposite聚合多个WebMvcConfigurer配置,统一调用 |
| 委托模式 | DelegatingWebMvcConfiguration不自行处理,全部委托给configurers |
| 模板方法模式 | ApplicationObjectSupport定义setApplicationContext流程,子类实现initApplicationContext |
| 策略模式 | MappedInterceptor封装路径匹配策略,运行时根据matches()决定是否生效 |
| 接口隔离 | 用户通过实现WebMvcConfigurer接口即可完成配置,无需继承复杂基类 |
第 13 章:关键源码位置速查
| 功能点 | 类名 | 方法名 |
|---|---|---|
| 收集配置 | DelegatingWebMvcConfiguration | setConfigurers |
| 存储配置 | WebMvcConfigurerComposite | addWebMvcConfigurers |
| 创建 HandlerMapping | WebMvcConfigurationSupport | requestMappingHandlerMapping |
| 触发拦截器收集 | WebMvcConfigurationSupport | getInterceptors |
| 委托 addInterceptors | DelegatingWebMvcConfiguration | addInterceptors |
| 遍历配置 | WebMvcConfigurerComposite | addInterceptors |
| 生成 MappedInterceptor | InterceptorRegistry | getInterceptors |
| 包装拦截器 | InterceptorRegistration | getInterceptor |
| 分类存储 | AbstractHandlerMapping | initInterceptors |
| 构建执行链 | AbstractHandlerMapping | getHandlerExecutionChain |
| 路径匹配 | MappedInterceptor | matches |
| 执行拦截器 | HandlerExecutionChain | applyPreHandle、applyPostHandle、triggerAfterCompletion |