适用读者:写过 Controller 但说不清"过滤器与拦截器谁先"的人。
前置:S07-B01。
实测环境:Spring Boot 3.3.6 / JDK 17(2026-11-05)。
覆盖旧文:2619(139) 982(84) 978(72) 984(82) 1740(74) 983(70) 1558(128) = 649 点。
覆盖扩展:E-S07-007(DispatcherServlet 与九大组件)。
上一篇:S07-B03 · AOP:切面、代理与失效场景
下一篇:S07-B05 · 自动配置与启动。
1. 一句话结论
请求先过 Servlet 过滤器(Filter),再进 DispatcherServlet,然后由拦截器(Interceptor)→ Controller → 返回值处理 → 异常解析走完。 顺序是硬性的,记住它就能定位"该在哪一层做校验/日志"。
实测(一次 GET 请求的日志顺序):
[1] Filter.doFilter 前
[2] Interceptor.preHandle
[3] Controller 执行
[4] Interceptor.afterCompletion
[5] Filter.doFilter 后
2. 完整链路(E-S07-007)
Tomcat → Filter 链 → DispatcherServlet
├─ HandlerMapping(找到 Controller 方法)
├─ HandlerInterceptor.preHandle
├─ HandlerAdapter(参数解析 + 调用)
├─ 返回值处理(@ResponseBody → HttpMessageConverter)
├─ HandlerInterceptor.postHandle
├─ 视图渲染(非 @ResponseBody 时)
├─ HandlerInterceptor.afterCompletion
└─ Filter 后置逻辑
异常分支 → HandlerExceptionResolver(@ControllerAdvice)
| 组件 | 职责 |
|---|---|
HandlerMapping |
URL → 处理方法 |
HandlerAdapter |
参数绑定、反射调用 |
HttpMessageConverter |
JSON ↔ 对象(Jackson) |
HandlerExceptionResolver |
异常 → 响应 |
3. Filter vs Interceptor vs Listener(A-984/A-1740)
| 维度 | Filter | Interceptor | Listener |
|---|---|---|---|
| 所属规范 | Servlet | Spring MVC | Servlet |
| 能否拿到 Bean | 需注入技巧 | ✅ 天然是 Bean | 需注意 |
| 能否拿到处理方法信息 | ❌ | ✅(HandlerMethod) |
❌ |
| 典型用途 | 编码、CORS、请求体包装 | 登录校验、日志、权限 | 启动/会话事件 |
判据:
需要"改请求/响应体"或"在 Spring 之前"处理 → Filter
需要"知道是哪个 Controller 方法" → Interceptor
需要"应用/会话生命周期事件" → Listener
实测顺序:Filter 包着 Interceptor([1] 最外,[5] 最外收尾)。
4. 参数绑定与校验
| 场景 | 注解 |
|---|---|
| 路径变量 | @PathVariable |
| 查询参数 | @RequestParam |
| 请求体 JSON | @RequestBody + @Valid |
| 表单 | @ModelAttribute |
| 头/Cookie | @RequestHeader / @CookieValue |
实测(校验失败):
[HTTP 400] {"errors":[{"msg":"must not be blank","field":"name"},
{"msg":"must be less than or equal to 120","field":"age"}]}
Spring 对 @Valid 失败默认抛 MethodArgumentNotValidException(→ 400),需要 @RestControllerAdvice 转成统一结构(B06)。
5. 三层架构(A-978)
| 层 | 职责 | 不该做什么 |
|---|---|---|
| Controller | 参数校验、编排、返回 | 写业务逻辑、直接写 SQL |
| Service | 业务规则、事务边界 | 处理 HTTP 细节 |
| Repository/Mapper | 数据访问 | 业务判断 |
判据:"这段逻辑换成 CLI 调用还需要吗?" 需要 → 应该在 Service。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "拦截器比过滤器早" | Filter 在最外层 |
| "Filter 里能拿到 Controller 方法" | 不能(Interceptor 才能) |
"@Valid 失败返回 500" |
返回 400(MethodArgumentNotValidException) |
| "Controller 可以写业务逻辑" | 会导致无法复用、难测试 |
"@ResponseBody 也要视图解析" |
不走视图,走 HttpMessageConverter |
7. 自检
- 一次请求的五步顺序(实测)?
- Filter 与 Interceptor 的三点差异?
- 什么时候必须用 Filter 而不是 Interceptor?
@Valid失败默认抛什么异常、返回什么状态码?- 三层架构里 Controller 不该做什么?
8. 下一篇
S07-B05 · Spring Boot:自动配置与启动流程
链路讲完,下一篇解释"为什么加个 starter 就有一堆 Bean",以及启动那 8–10 秒花在哪。
本篇属于系列《S07 · Spring 框架》。旧文来源:A-2619/982/978/984/1740/983/1558;扩展点 E-S07-007。Filter/Interceptor 顺序与 400 响应为 Spring Boot 3.3.6 实测。