Gateway 中能写 Servlet Filter 吗?

  • [Gateway 中能写 Servlet Filter 吗?(补充版)](#Gateway 中能写 Servlet Filter 吗?(补充版))
    • [1. Spring Boot 自带 Tomcat,为什么 Filter 不执行?](#1. Spring Boot 自带 Tomcat,为什么 Filter 不执行?)
    • [2. Mono 和 Flux 是啥?为啥 Gateway 非要用它们?](#2. Mono 和 Flux 是啥?为啥 Gateway 非要用它们?)
    • [3. Netty 是个什么东西?](#3. Netty 是个什么东西?)
    • 总结一下

这个问题我之前也困惑过一阵子。因为刚接触 Spring Cloud Gateway 的时候,脑子里还带着以前用 Spring MVC 或者传统 Web 应用的思维------动不动就想加个 Filter 来处理请求日志、鉴权、跨域啥的。

但后来发现,Gateway 和传统的 Servlet 容器压根不是一个路子。今天就聊聊我的理解,顺便说说怎么在 Gateway 里"做类似 Filter 的事"。


Gateway 不是跑在 Servlet 容器上的

这点很重要。Spring Cloud Gateway 是基于 Reactor 模型构建的,底层用的是 Netty,而不是 Tomcat、Jetty 这些我们熟悉的 Servlet 容器。

而 javax.servlet.Filter(或者 jakarta.servlet.Filter)这个接口,是 Servlet 规范的一部分 。它只能在支持 Servlet 的容器里运行。所以,如果你硬要在 Gateway 项目里写一个 @Component 注解的 Filter,它根本不会被调用------因为 Netty 根本不认识它。

我一开始不信邪,写了下面这段代码:

java 复制代码
@Component
public class MyServletFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("我在 Gateway 里打印这句话");
        chain.doFilter(request, response);
    }
}

结果?启动正常,但发任何请求,控制台都没输出。白忙活一场。


那 Gateway 用什么代替 Filter?

答案是:GlobalFilter 和 GatewayFilter。

这两兄弟才是 Gateway 世界的"过滤器"。它们不是 Servlet 那一套,而是响应式编程模型下的组件。

全局过滤器(GlobalFilter)

如果你希望对所有路由都生效,比如统一记录请求耗时、统一鉴权,那就写个 GlobalFilter:

java 复制代码
@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        long start = System.currentTimeMillis();
        ServerHttpRequest request = exchange.getRequest();
        System.out.println("请求来了: " + request.getURI());

        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            long end = System.currentTimeMillis();
            System.out.println("请求结束,耗时: " + (end - start) + "ms");
        }));
    }

    @Override
    public int getOrder() {
        return -1; // 数字越小,优先级越高
    }
}

注意这里返回的是 Mono<Void>,整个流程是异步非阻塞的。你不能像在 Servlet Filter 里那样直接 chain.doFilter() 就完事,得用 then()、flatMap() 这些操作符来组合逻辑。

局部过滤器(GatewayFilter)

如果只想对某个特定路由加逻辑,比如给 /api/user/** 加个 token 校验,可以在配置文件里配,也可以自定义 GatewayFilterFactory。

举个简单的例子,在 application.yml 里加个内置的过滤器:

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - AddRequestHeader=X-Source, gateway

这会给匹配的请求加上一个请求头。当然,你也可以自己写复杂的逻辑,比如解析 JWT、修改请求体等。


我们的经验是......

在团队迁移老项目到 Gateway 的过程中,最常踩的坑就是"想当然地用 Servlet 思维写代码"。比如:

  • 试图在 Gateway 里用 HttpServletRequest ------ 不行,得用 ServerHttpRequest
  • 想用 ThreadLocal 存用户信息 ------ 响应式环境下线程会切换,得用 Context 或 Reactor Context
  • 直接调用阻塞的数据库或 HTTP 接口 ------ 会导致性能瓶颈,最好用 WebClient 等非阻塞方式

所以我的建议是:一旦用了 Gateway,就彻底告别 Servlet 那套东西。别想着"能不能兼容",而是"怎么用新模型解决问题"。


Gateway 中能写 Servlet Filter 吗?(补充版)

上面讲了 Gateway 不能用 Servlet Filter,但我觉得有些问题还需要补充一下:"Spring Boot 不是自带 Tomcat 吗?为啥 Filter 不生效?" 、"Mono/Flux 到底是啥?" 、"Netty 又是个什么玩意儿?"

这些问题其实戳中了很多人迁移微服务网关时的认知盲区。我就结合我们踩过的坑,再唠一唠。


1. Spring Boot 自带 Tomcat,为什么 Filter 不执行?

这是个特别容易混淆的点!我一开始也纳闷:明明项目是 Spring Boot 啊,application.properties 里也没改啥,怎么 Filter 就不跑了?

关键在于:你启动的是不是"WebFlux"应用?

Spring Boot 从 2.x 开始,支持两种 Web 编程模型:

  • Spring MVC :基于 Servlet,跑在 Tomcat/Jetty 上,用 DispatcherServlet 处理请求。
  • Spring WebFlux:响应式编程模型,可以跑在 Netty、Undertow,甚至也能跑在 Tomcat 上(但不用 Servlet 那套)。

而 Spring Cloud Gateway 是基于 WebFlux 构建的 。就算你没显式排除 Tomcat,只要引入了 spring-cloud-starter-gateway,Spring Boot 会自动切换成 WebFlux 模式 ,并且默认使用 Netty 作为内嵌服务器。

你可以试试看:启动一个纯 Gateway 项目,控制台会打印类似这样的日志:

复制代码
Netty started on port 8080

而不是:

复制代码
Tomcat started on port 8080

📌 重点来了 :即使你强行保留 Tomcat(比如加了 spring-boot-starter-web),只要用了 Gateway,它内部的路由和过滤逻辑依然是走 WebFlux + Reactor 的,不会经过 Servlet 容器的 Filter 链 。所以你写的 @Component Filter 根本没机会被调用。

我们的经验是:Gateway 项目里千万别同时引入 spring-boot-starter-web 和 spring-cloud-starter-gateway,否则会冲突,启动都可能失败。


2. Mono 和 Flux 是啥?为啥 Gateway 非要用它们?

简单说,Mono 和 Flux 是 Project Reactor 提供的两个核心类,用来做响应式编程(Reactive Programming)。

  • Mono<T>:表示 0 或 1 个元素的异步流。比如一个 HTTP 响应、一个用户对象。
  • Flux<T>:表示 0 到 N 个元素的异步流。比如一个消息队列、一个文件流。

它们和传统的 List、User 有什么区别?最大的不同是:它们不代表"已经拿到的数据",而是"未来会拿到数据的承诺"。

举个例子:

java 复制代码
// 传统方式(阻塞)
User user = userService.findById(1); // 线程卡在这儿,等数据库返回

// 响应式方式(非阻塞)
Mono<User> userMono = userService.findById(1); // 立刻返回,不等!

在 Gateway 的 GlobalFilter 里,你看到的这个方法签名:

java 复制代码
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)

意思就是:"我处理完这个请求后,会给你一个信号(Void),但我不阻塞线程"。整个链路靠 Mono 的组合(比如 .then(), .flatMap())来串联。

为什么 Gateway 要用这套?

因为网关要扛高并发。如果每个请求都占一个线程(像 Tomcat 那样),1万个并发就得开1万个线程,内存直接爆掉。而 Netty + Reactor 用少量线程就能处理几万甚至几十万连接------靠的就是"非阻塞 + 异步回调"。

所以,不是 Gateway "非要搞复杂",而是为了性能不得不这么干。


3. Netty 是个什么东西?

你可以把 Netty 理解为一个 高性能网络通信框架。它不依赖 Servlet 规范,直接跟操作系统底层的网络接口打交道(比如 Linux 的 epoll)。

Tomcat 是"面向请求-响应"的:来一个 HTTP 请求 → 分配一个线程 → 处理 → 返回 → 线程释放。

Netty 是"事件驱动"的:所有连接注册到 EventLoop(可以理解为一个线程池),当有数据可读/可写时,才触发回调。一个线程能同时管成百上千个连接。

Spring Cloud Gateway 选择 Netty,就是因为:

  • 启动快
  • 内存占用低
  • 支持长连接、WebSocket、HTTP/2 等高级特性
  • 天然契合响应式编程模型

打个比方:

  • Tomcat 像是"每个顾客配一个服务员",人多了就忙不过来。
  • Netty 像是"一个服务员盯所有桌子,谁举手就服务谁",效率高得多。

当然,Netty 学习曲线陡一点,调试也麻烦些。但对网关这种 I/O 密集型场景,它是目前 Java 生态里最成熟的选择。


总结一下

  • 不能 在 Spring Cloud Gateway 中使用 Servlet Filter,因为它不跑在 Servlet 容器上。
  • 要实现类似功能,请用 GlobalFilter 或 GatewayFilter。
  • 别硬套旧习惯,响应式编程有它自己的套路,适应了其实也挺香。
  • 如果你只是做个后台管理,QPS 几十,用 Spring MVC + Tomcat 完全够用,Filter 写起来也顺手。
  • 但如果你要做 API 网关,面对的是成千上万的移动端或第三方调用,那 Gateway + Netty + Reactor 这套组合拳,就是更合适的选择。

我自己现在写 Gateway 项目,已经完全不用 Filter 这个词了,一说"过滤器",默认就是指 GlobalFilter。思维转过来之后,开发反而更清爽。

希望这篇碎碎念能帮到和我当初一样迷糊的朋友。

相关推荐
程序员清风11 小时前
Portkey AI Gateway 实战:构建可治理的多模型网关
人工智能·gateway
JJJennie77711 小时前
大模型网关能做故障转移吗?MAI Gateway如何赋能企业AI能力
ai·gateway·ai网关·企业网关
大猫和小黄1 天前
从 Servlet 到 SSM:Java Web 进化史
servlet·java web
需要8267 天前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
Raas1008 天前
MAI Gateway(魔芋企业级AI网关)功能全解:AI网关支持流式输出吗?一文看懂AI网关能力矩阵
大数据·人工智能·gateway·mai gateway·企业级网关
毅炼9 天前
不写多语言 SDK,怎么让 Python、Go、Node 服务接入注册中心?
java·后端·系统架构·gateway
Raas10012 天前
AI网关支持哪些模型?MAI Gateway(魔芋企业级AI网关)功能实测与最佳实践
大数据·人工智能·gateway·mai gateway·企业级产品
Raas10012 天前
MAI Gateway(魔芋企业级AI网关)技术揭秘:AI网关支持DeepSeek吗?从原理到落地
大数据·人工智能·gateway·ai网关·mai gateway·魔芋·企业级产品
Raas10013 天前
MAI Gateway(魔芋企业级AI网关)技术揭秘:AI网关支持哪些模型?从原理到落地
大数据·人工智能·网关·gateway·mai gateway·企业级产品