在 Spring 中,拦截器和过滤器有什么区别?
- 标签:Spring、Java
🏛 业务架构师
拦截器(HandlerInterceptor)和过滤器(Filter)的区别,核心是所属体系与作用时机:
- Filter 是 Servlet 规范的组件:在请求进入 Spring MVC 之前、响应离开之后工作(filter chain 最外层),能拿到原始请求响应,但感知不到 Handler 是谁;
- Interceptor 是 Spring MVC 的组件:在 DispatcherServlet 之后、Handler 执行前后介入,能拿到 handler 信息(方法、注解),且可使用 Spring 容器能力。
业务架构师视角,我按治理职责分层来分配它们:
- Filter 层放"协议级/横切基础设施":全链路最外层的字符编码、CORS、全局 traceId 注入、请求体日志(审计需要原始报文时)、防 XSS 清洗——这些不关心业务路由,越早执行越好;
- Interceptor 层放"业务路由感知"的治理:鉴权(知道要调哪个接口、能读方法上的权限注解)、用户/租户上下文注入、接口级访问日志与耗时、灰度标记——需要"这是哪个业务接口"的信息才能做对;
- 顺序上 Filter 先于 Interceptor 执行。一个典型的完整链:
Filter(traceId/CORS) → Interceptor(鉴权/上下文) → Controller。
实践提醒:Spring Boot 里自定义 Filter 有两种注册方式(@WebFilter+@ServletComponentScan 或 FilterRegistrationBean),用后者才能精确控制顺序和 URL 匹配——顺序错误的鉴权过滤器是真实安全事故来源。
🏗 系统架构师
六个维度对比:
| 维度 | Filter | Interceptor |
|---|---|---|
| 规范 | Servlet 规范 | Spring MVC |
| 范围 | 所有请求(含静态资源) | 只到 Handler 层 |
| 上下文 | Servlet 体系 | 天然是容器 Bean |
| 粒度 | 请求级 | 拿得到 HandlerMethod 元数据(方法、注解) |
| 时机 | 最外层,先于 DispatcherServlet | Filter 之后、Controller 之前 |
| 用途 | 编码、CORS、安全头、XSS | 认证鉴权、traceId、审计、灰度 |
我的分层放置原则:
- 与协议/容器相关放 Filter(它不该理解 Spring);
- 与业务路由相关(要读注解、区分接口)放 Interceptor;
- 跨服务统一的横切(限流、熔断、请求清洗)上收网关,应用内只留本地校验。
执行时序:Filter 链 → DispatcherServlet → Interceptor preHandle → Controller → postHandle → afterCompletion → Filter 返回。画得出这条时序,MDC 泄漏、清理乱序这类问题才排得动。
💻 全栈开发专家
同是横切手段,层次和出身不同:
| 维度 | Filter 过滤器 | Interceptor 拦截器 |
|---|---|---|
| 规范 | Servlet 规范 | Spring MVC 机制 |
| 位置 | 最外层,DispatcherServlet 之前 | DispatcherServlet 内、handler 前后 |
| 能拿到什么 | 原始 request/response | handler 方法元数据(HandlerMethod、注解) |
| 典型场景 | 编码、CORS、XSS 过滤、请求体包装 | 登录态、权限、接口审计 |
| 异常 | 抛错到不了 @ControllerAdvice | 能被全局异常处理器接住 |
| Bean 注入 | DelegatingFilterProxy 或手动 | 天然是 Spring Bean |
执行顺序:Filter chain 前 → Interceptor preHandle → Controller → postHandle → afterCompletion → Filter chain 后。
选型口诀:协议/容器层面的事给 Filter,业务语义的事给 Interceptor。实例对比:全局访问日志要重复读 body,必须 Filter + ContentCachingRequestWrapper;"只对带 @RequirePermission 注解的接口鉴权"必须 Interceptor(Filter 看不到方法注解)。Spring Security 本质是一组 Filter(FilterChainProxy),所以在 MVC 拦截器之前生效——这条最能体现层次理解。