Spring配置拦截器的核心答案是:通过实现HandlerInterceptor接口并注册到Spring MVC的拦截器注册表中,登录鉴权、日志记录、接口防重等横切逻辑就能在Controller方法执行前后自动运行。这套机制在Spring Boot项目中通常只需要一个@Configuration类加上几行addInterceptors代码,但在Spring传统XML项目中则是另一套配置路径,下面把三种主流配置方式、常见坑位以及和过滤器(Filter)的本质区别一次讲透。
用代码配置拦截器:从Spring Boot到传统项目的完整姿势
Spring Boot下的Java Config配置(最常用)
在Spring Boot 2.x和3.x环境下,配置拦截器的标准姿势是写一个配置类,实现WebMvcConfigurer接口,重写addInterceptors方法,这是目前绝大多数项目的选项路径。
- 第一步:自定义拦截器类,实现HandlerInterceptor接口,在preHandle、postHandle、afterCompletion三个方法中写业务逻辑。
- 第二步:注册拦截器,使用@Configuration注解的类继承WebMvcConfigurer,调用registry.addInterceptor()方法添加。
- 第三步:通过addPathPatterns指定拦截路径,用excludePathPatterns放行登录、注册、静态资源等路径。
以一个登录校验拦截器为例,preHandle中从request的Header或Session中取出Token,若为空则直接返回false并写入“未授权”JSON响应,这种写法相比在每个Controller里重复判断代码,维护成本低一个量级。
传统Spring XML项目的配置方法
不少遗留系统依然使用Spring MVC的XML配置方式,在spring-mvc.xml中,通过
一个容易踩坑的注册细节
如果项目中使用Spring Security,注册拦截器的配置类上需要加@EnableWebMvc注解吗?一般不推荐加,加了@EnableWebMvc会全面接管WebMvc配置,导致静态资源映射、消息转换器等默认配置失效,多数情况下会出现“配置了拦截器但CSS、JS全部404”的现象,处理费时费力。

spring拦截器不生效的5大排查路径
按拦截器配置失败的常见原因,按下述顺序检查可较快定位问题:
- 项目是否引入了spring-webmvc依赖,仅依赖spring-context时不会触发WebMvcConfigurer机制。
- 自定义拦截器类上是否标注@Component或交由Spring容器管理,注册时若直接new一个拦截器实例,其中的依赖注入全部为null,preHandle里调用Service必然抛空指针。
- 路径匹配规则是否写对,/匹配所有路径,/只匹配一层路径,/api/不匹配/api/user/detail这种多级路径。
- Spring Boot版本差异:Spring Boot 2.x用WebMvcConfigurer没问题,Spring Boot 3.x基于Jakarta Servlet的API,拦截器方法签名没有变化,但依赖包名变化会编不过。
- 多拦截器顺序问题:后注册的拦截器preHandle先执行,postHandle和afterCompletion逆序执行,若A拦截器放行了请求但B拦截器阻止,A的afterCompletion依然会执行,这在业务上容易造成“日志记录了但接口其实没成功”的误会。
spring拦截器和过滤器区别的对比梳理
很多初级开发者分不清Filter和Interceptor的边界,从执行时机来看:Filter由Servlet容器管理,在请求进入DispatcherServlet之前执行;Interceptor在DispatcherServlet匹配到具体Handler之后执行,从使用场景看,Filter更适合处理编码设置、跨域CORS、请求体流读取这类Web层通用逻辑,而Interceptor更贴合Spring MVC的Handler执行链路,可以直接拿到HandlerMethod、ModelAndView等MVC相关对象。
| 对比维度 | Filter(过滤器) | Interceptor(拦截器) |
|---|---|---|
| 规范归属 | Servlet规范 | Spring MVC规范 |
| 执行时机 | 进入DispatcherServlet之前 | Handler执行之前/之后 |
| 能否获取Spring Bean | 可以注入但需容器管理 | 天然支持,可直接注入 |
| 典型场景 | 字符编码、跨域、请求日志 | 登录校验、权限控制、接口幂等 |
| 终止方式 | 直接返回响应 | 返回false并写入响应 |
从配置到实战:一个完整的登录拦截器实例与性能考量
写一个可运行的登录校验拦截器,多数实际项目还会搭配用户权限标识动态下发,业界通常的做法是:preHandle中从请求头读取token,调用自定义的TokenService验证有效期,若token剩余有效时间低于阈值则刷新并写入响应头,这个逻辑放在拦截器里比放在Controller里更加优雅。
拦截器中的异步请求与性能监控
当接口中使用Callable或DeferredResult处理异步逻辑时,postHandle不会在业务线程执行后继续触发,需要在异步请求完成时通过WebAsyncManager注册拦截器,若没有注册,性能监控类拦截器在异步接口下会漏记日志。
登录拦截器里放行路径顺序有讲究
分两批放行效果更清晰:
- 第一批:静态资源,/static/、/favicon.ico、/error。
- 第二批:白名单接口:/login、/captcha、/api/register,优先使用精确路径匹配而不是/通配符兜底。
这样配置后,后续只要在Controller路径上做权限注解标注,就行之有效,而不必频繁改动拦截器。
实战中的多拦截器链与顺序控制
业务复杂时,通常会配置多个拦截器分别处理日志、登录校验、权限校验、接口幂等,注册顺序就是执行顺序,先注册的外层先执行preHandle,具体配置时的操作经验是:把通用性强的放前面,业务性强的放后面。
三个拦截器配置示例路径:
- 第一个:AccessLogInterceptor,打印请求方法、URI、耗时,使用/路径。
- 第二个:AuthInterceptor,校验用户身份,使用/api/路径,排除/login。
- 第三个:RateLimitInterceptor,基于Redis限流,使用//write等写接口路径。

在排除路径列表中,需要把文档接口(如swagger-ui、/v3/api-docs)排除掉,否则在开发环境调试接口时突遇登录跳转会降低联调效率。
Spring配置拦截器后的性能收益与常见误区
配置拦截器维护横切逻辑,相比在Controller中复制粘贴代码,性能上只是多了一次方法调用和一次布尔判断,开销很小,真正的性能瓶颈常出现在拦截器中执行了数据库查询、远程RPC调用这类重量级操作,尤其在高并发下接口访问量较大时,容易拖慢请求链路,建议把拦截器内的逻辑保持轻量,避免在这个位置访问第三方接口或执行耗时聚合操作,多数情况下,将用户信息查询从拦截器挪到Controller内按需加载,能有效降低无权限请求的资源消耗。
关于Spring拦截器配置有哪些常见疑问
spring拦截器配置方法有哪些?
配置拦截器有Java Config和XML两种主流方式,Java Config使用WebMvcConfigurer接口配合addInterceptors方法注册,XML使用mvc:interceptors标签声明,Spring Boot项目采用Java Config的方式更加简洁,同时支持路径匹配和排除规则的高度定制。
登录拦截器里校验不通过时如何返回JSON?
在preHandle中使用response.setContentType(“application/json;charset=UTF-8”),然后通过response.getWriter().write(JSON字符串)直接输出统一响应体,最后return false终止请求,注意此时不要直接使用HttpServletResponse.sendRedirect,那样会导致前后端分离模式下前端拿不到结构化错误信息。
拦截器和AOP的关系是什么?
拦截器基于Servlet容器的调用链机制,在Handler执行前后回调,天然适配MVC层,而AOP基于Spring容器管理的Bean代理,可以切到Service层的任意方法,实现更细粒度的日志、事务、权限逻辑,两者并不冲突,执行层级和执行目标不同,在实际工程中常常搭配使用。

