Filter、Interceptor、AOP 谁先执行?跟着请求走一遍
看到这篇文章,让我想到了文章里讲的
Filter 属于 Servlet 规范,由 Tomcat 调用,跑在 DispatcherServlet 之前,所以在最外层,连静态资源的请求都会经过它。
Interceptor 属于 Spring MVC,由 DispatcherServlet 找到处理器之后调用。
AOP 是 Spring 的代理机制,作用在 Controller 方法的调用上,贴得最近。
延伸一下,就到了 Servlet 栈(Spring MVC)
WebFlux 栈(Spring WebFlux)。
Servlet 栈(Spring MVC)
┌─────────────────────────────────────────────────────────────┐ │ Client Request │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Web Container (Tomcat/Jetty) │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ Filter Chain (javax.servlet.Filter) │ │ │ │ Filter1 → Filter2 → ... → FilterN │ │ │ └───────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ DispatcherServlet │ │ │ │ ① HandlerMapping → 找到 HandlerMethod │ │ │ │ ② HandlerAdapter → 调用 Controller │ │ │ │ ③ HandlerInterceptor.preHandle() ◀── 注意这里 │ │ │ │ ④ 执行 @Controller 方法 │ │ │ │ ⑤ HandlerInterceptor.postHandle() ◀── 注意这里 │ │ │ │ ⑥ 渲染视图 / 写响应 │ │ │ │ ⑦ HandlerInterceptor.afterCompletion() ◀── 注意 │ │ │ └───────────────────────────┬───────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ HttpServletResponse (阻塞式输出) │ │ │ └───────────────────────────┬───────────────────────────┘ │ └──────────────────────────────┼──────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Client Response │ └─────────────────────────────────────────────────────────────┘关键特征:Filter 是 Servlet 规范定义的,Interceptor 是 Spring MVC 框架自己加的。
WebFlux 栈(Spring WebFlux)
┌─────────────────────────────────────────────────────────────┐ │ Client Request │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Reactive Server (Netty / Undertow / Servlet3.1) │ │ (没有统一容器规范,各服务器私有 API) │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ HttpHandler (Spring 适配层,屏蔽服务器差异) │ │ ServerHttpRequest + ServerHttpResponse → Mono<Void> │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ WebFilter Chain (org.springframework.web.server.) │ │ WebFilter1 → WebFilter2 → ... → WebFilterN │ │ 对应 Servlet Filter,但是返回 Mono<Void>(响应式) │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ DispatcherHandler │ │ ① HandlerMapping → 找到 handler(不一定是 Method) │ │ ② HandlerAdapter → 调用 handler │ │ ③ 没有 HandlerInterceptor! │ │ ├── 前置逻辑 → 写在 WebFilter 里 │ │ ├── 后置逻辑 → 写在 WebFilter 里(或 doOnSuccess) │ │ └── 异常处理 → WebFilter 的 onErrorResume │ │ ④ Controller 返回 Mono / Flux │ │ ⑤ HandlerResultHandler → 序列化并写响应 │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ServerHttpResponse(非阻塞、背压感知、流式写入) │ └─────────────────────────────┬───────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Client Response │ └─────────────────────────────────────────────────────────────┘关键特征:没有 Filter 规范、没有 Interceptor,一切靠WebFilter+Mono操作符链。
逐层对照表
层次 | Servlet / Spring MVC | WebFlux / Reactive |
|---|---|---|
规范层 |
| 无容器规范,只有 |
服务器 | Tomcat / Jetty (Servlet 模式) | Netty / Undertow / Tomcat(3.1 NIO) |
服务器→框架适配 | Servlet API 直接对接 |
|
全局前置/后置 |
|
|
中央调度器 |
|
|
路由/映射 |
|
|
处理器前后拦截 | ✅ | ❌ 没有,用 |
参数解析/返回值处理 |
|
|
响应写入 |
|
|
异常处理 |
|
|
一句话总结差异本质
Servlet 栈: 规范定义容器 → 容器定义 Filter → 框架加 Interceptor → 阻塞 I/O
WebFlux 栈: 无容器规范 → 框架自己适配服务器 → 只有 WebFilter → 响应式流 + 背压
三者(Undertow / Jetty / Tomcat)在 WebFlux 下的真实定位
服务器 | WebFlux 使用方式 | 非阻塞纯度 | 说明 |
|---|---|---|---|
Netty | Reactor Netty 直连 | 最高 | EventLoop + 全链路响应式,WebFlux 默认 |
Undertow | Undertow API 直连(非 Servlet) | 高 | XNIO 事件模型,适合响应式,轻量 |
Jetty | Servlet 3.1 NIO 适配 | 中 | 能跑,但走 Servlet 非阻塞桥 |
Tomcat | Servlet 3.1 NIO 适配 | 中 | 同上,线程池模型偏传统 |
Netty是响应式最好的,Undertow次之,其他的servlet容器最差。
- Undertow 严格说不算"次之",而是"和 Netty 同一档但生态弱一截"——它走的是 XNIO 事件模型,不是 Servlet 适配,非阻塞纯度其实很高。只是 Reactor Netty 跟 Spring WebFlux 是同一个团队(reactor 项目)出的,磨合最好、文档最全、踩坑最少。
- Tomcat/Jetty 不是"差",是"定位不同"——它们本来就是为 Servlet 同步模型设计的,响应式是后来硬桥上去的。能跑,但线程模型、内存占用、长连接表现都拼不过原生响应式底座。
所以更准确的说法是:
Netty ≈ Undertow(原生响应式底座)> Tomcat ≈ Jetty(Servlet 适配桥接)
选谁就看你场景——新项目无历史包袱直接 Netty;已有 Undertow 技术栈直接上 WebFlux 完全没问题;老项目想试水响应式又不想换容器,Tomcat/Jetty 也能跑,别指望性能飞跃就行。