☰
Spring MVC 拦截器源码深度解析:从配置到匹配
2026/10/21 5:15:13 网站建设 项目流程

目录

    • 第一部分:启动阶段 —— 拦截器的配置、收集、包装与存储
      • 第 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()方法,这个方法会执行以下操作:

  1. 创建一个InterceptorRegistry实例。
  2. 调用addInterceptors(registry)(这是一个由子类DelegatingWebMvcConfiguration重写的方法)。
  3. 调用registry.getInterceptors()将注册信息转换为Object[]数组,其中包含MappedInterceptor和普通拦截器。
  4. 将这个数组设置给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 章:关键源码位置速查

功能点类名方法名
收集配置DelegatingWebMvcConfigurationsetConfigurers
存储配置WebMvcConfigurerCompositeaddWebMvcConfigurers
创建 HandlerMappingWebMvcConfigurationSupportrequestMappingHandlerMapping
触发拦截器收集WebMvcConfigurationSupportgetInterceptors
委托 addInterceptorsDelegatingWebMvcConfigurationaddInterceptors
遍历配置WebMvcConfigurerCompositeaddInterceptors
生成 MappedInterceptorInterceptorRegistrygetInterceptors
包装拦截器InterceptorRegistrationgetInterceptor
分类存储AbstractHandlerMappinginitInterceptors
构建执行链AbstractHandlerMappinggetHandlerExecutionChain
路径匹配MappedInterceptormatches
执行拦截器HandlerExecutionChainapplyPreHandle、applyPostHandle、triggerAfterCompletion

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询