最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Gateway 中是否能寫 Servlet Filter

 更新時(shí)間:2025年12月25日 16:01:22   作者:Tech_Jia_Hui  
在SpringCloudGateway中不能使用ServletFilter,因?yàn)樗腔赗eactor模型構(gòu)建的,底層用的是Netty,而不是Tomcat、Jetty這些Servlet容器,要實(shí)現(xiàn)類似功能,請(qǐng)用GlobalFilter或GatewayFilter,本文給大家解析Gateway中能寫Servlet Filter嗎,感興趣的朋友一起看看吧

這個(gè)問題我之前也困惑過一陣子。因?yàn)閯偨佑| Spring Cloud Gateway 的時(shí)候,腦子里還帶著以前用 Spring MVC 或者傳統(tǒng) Web 應(yīng)用的思維——動(dòng)不動(dòng)就想加個(gè) Filter 來處理請(qǐng)求日志、鑒權(quán)、跨域啥的。

但后來發(fā)現(xiàn),Gateway 和傳統(tǒng)的 Servlet 容器壓根不是一個(gè)路子。今天就聊聊我的理解,順便說說怎么在 Gateway 里“做類似 Filter 的事”。

Gateway 不是跑在 Servlet 容器上的

這點(diǎn)很重要。Spring Cloud Gateway 是基于 Reactor 模型構(gòu)建的,底層用的是 Netty,而不是 Tomcat、Jetty 這些我們熟悉的 Servlet 容器。

javax.servlet.Filter(或者 jakarta.servlet.Filter)這個(gè)接口,是 Servlet 規(guī)范的一部分。它只能在支持 Servlet 的容器里運(yùn)行。所以,如果你硬要在 Gateway 項(xiàng)目里寫一個(gè) @Component 注解的 Filter,它根本不會(huì)被調(diào)用——因?yàn)?Netty 根本不認(rèn)識(shí)它。

我一開始不信邪,寫了下面這段代碼:

@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);
    }
}

結(jié)果?啟動(dòng)正常,但發(fā)任何請(qǐng)求,控制臺(tái)都沒輸出。白忙活一場(chǎng)。

那 Gateway 用什么代替 Filter?

答案是:GlobalFilterGatewayFilter

這兩兄弟才是 Gateway 世界的“過濾器”。它們不是 Servlet 那一套,而是響應(yīng)式編程模型下的組件。

全局過濾器(GlobalFilter)

如果你希望對(duì)所有路由都生效,比如統(tǒng)一記錄請(qǐng)求耗時(shí)、統(tǒng)一鑒權(quán),那就寫個(gè) GlobalFilter

@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("請(qǐng)求來了: " + request.getURI());
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            long end = System.currentTimeMillis();
            System.out.println("請(qǐng)求結(jié)束,耗時(shí): " + (end - start) + "ms");
        }));
    }
    @Override
    public int getOrder() {
        return -1; // 數(shù)字越小,優(yōu)先級(jí)越高
    }
}

注意這里返回的是 Mono<Void>,整個(gè)流程是異步非阻塞的。你不能像在 Servlet Filter 里那樣直接 chain.doFilter() 就完事,得用 then()、flatMap() 這些操作符來組合邏輯。

局部過濾器(GatewayFilter)

如果只想對(duì)某個(gè)特定路由加邏輯,比如給 /api/user/** 加個(gè) token 校驗(yàn),可以在配置文件里配,也可以自定義 GatewayFilterFactory

舉個(gè)簡(jiǎn)單的例子,在 application.yml 里加個(gè)內(nèi)置的過濾器:

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

這會(huì)給匹配的請(qǐng)求加上一個(gè)請(qǐng)求頭。當(dāng)然,你也可以自己寫復(fù)雜的邏輯,比如解析 JWT、修改請(qǐng)求體等。

我們的經(jīng)驗(yàn)是……

在團(tuán)隊(duì)遷移老項(xiàng)目到 Gateway 的過程中,最常踩的坑就是“想當(dāng)然地用 Servlet 思維寫代碼”。比如:

  • 試圖在 Gateway 里用 HttpServletRequest —— 不行,得用 ServerHttpRequest
  • 想用 ThreadLocal 存用戶信息 —— 響應(yīng)式環(huán)境下線程會(huì)切換,得用 ContextReactor Context
  • 直接調(diào)用阻塞的數(shù)據(jù)庫或 HTTP 接口 —— 會(huì)導(dǎo)致性能瓶頸,最好用 WebClient 等非阻塞方式

所以我的建議是:一旦用了 Gateway,就徹底告別 Servlet 那套東西。別想著“能不能兼容”,而是“怎么用新模型解決問題”。

Gateway 中能寫 Servlet Filter 嗎?(補(bǔ)充版)

上面講了 Gateway 不能用 Servlet Filter,但我覺得有些問題還需要補(bǔ)充一下:“Spring Boot 不是自帶 Tomcat 嗎?為啥 Filter 不生效?”、“Mono/Flux 到底是啥?”、“Netty 又是個(gè)什么玩意兒?”

這些問題其實(shí)戳中了很多人遷移微服務(wù)網(wǎng)關(guān)時(shí)的認(rèn)知盲區(qū)。我就結(jié)合我們踩過的坑,再嘮一嘮。

1. Spring Boot 自帶 Tomcat,為什么 Filter 不執(zhí)行?

這是個(gè)特別容易混淆的點(diǎn)!我一開始也納悶:明明項(xiàng)目是 Spring Boot 啊,application.properties 里也沒改啥,怎么 Filter 就不跑了?

關(guān)鍵在于:你啟動(dòng)的是不是“WebFlux”應(yīng)用?

Spring Boot 從 2.x 開始,支持兩種 Web 編程模型:

  • Spring MVC:基于 Servlet,跑在 Tomcat/Jetty 上,用 DispatcherServlet 處理請(qǐng)求。
  • Spring WebFlux:響應(yīng)式編程模型,可以跑在 Netty、Undertow,甚至也能跑在 Tomcat 上(但不用 Servlet 那套)。

Spring Cloud Gateway 是基于 WebFlux 構(gòu)建的。就算你沒顯式排除 Tomcat,只要引入了 spring-cloud-starter-gateway,Spring Boot 會(huì)自動(dòng)切換成 WebFlux 模式,并且默認(rèn)使用 Netty 作為內(nèi)嵌服務(wù)器。

你可以試試看:?jiǎn)?dòng)一個(gè)純 Gateway 項(xiàng)目,控制臺(tái)會(huì)打印類似這樣的日志:

Netty started on port 8080

而不是:

Tomcat started on port 8080

?? 重點(diǎn)來了:即使你強(qiáng)行保留 Tomcat(比如加了 spring-boot-starter-web),只要用了 Gateway,它內(nèi)部的路由和過濾邏輯依然是走 WebFlux + Reactor 的,不會(huì)經(jīng)過 Servlet 容器的 Filter 鏈。所以你寫的 @Component Filter 根本沒機(jī)會(huì)被調(diào)用。

我們的經(jīng)驗(yàn)是:Gateway 項(xiàng)目里千萬別同時(shí)引入 spring-boot-starter-webspring-cloud-starter-gateway,否則會(huì)沖突,啟動(dòng)都可能失敗。

2. Mono 和 Flux 是啥?為啥 Gateway 非要用它們?

簡(jiǎn)單說,MonoFluxProject Reactor 提供的兩個(gè)核心類,用來做響應(yīng)式編程(Reactive Programming)。

  • Mono<T>:表示 0 或 1 個(gè)元素的異步流。比如一個(gè) HTTP 響應(yīng)、一個(gè)用戶對(duì)象。
  • Flux<T>:表示 0 到 N 個(gè)元素的異步流。比如一個(gè)消息隊(duì)列、一個(gè)文件流。

它們和傳統(tǒng)的 List、User 有什么區(qū)別?最大的不同是:它們不代表“已經(jīng)拿到的數(shù)據(jù)”,而是“未來會(huì)拿到數(shù)據(jù)的承諾”。

舉個(gè)例子:

// 傳統(tǒng)方式(阻塞)
User user = userService.findById(1); // 線程卡在這兒,等數(shù)據(jù)庫返回
// 響應(yīng)式方式(非阻塞)
Mono<User> userMono = userService.findById(1); // 立刻返回,不等!

在 Gateway 的 GlobalFilter 里,你看到的這個(gè)方法簽名:

Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)

意思就是:“我處理完這個(gè)請(qǐng)求后,會(huì)給你一個(gè)信號(hào)(Void),但我不阻塞線程”。整個(gè)鏈路靠 Mono 的組合(比如 .then(), .flatMap())來串聯(lián)。

為什么 Gateway 要用這套?

因?yàn)榫W(wǎng)關(guān)要扛高并發(fā)。如果每個(gè)請(qǐng)求都占一個(gè)線程(像 Tomcat 那樣),1萬個(gè)并發(fā)就得開1萬個(gè)線程,內(nèi)存直接爆掉。而 Netty + Reactor 用少量線程就能處理幾萬甚至幾十萬連接——靠的就是“非阻塞 + 異步回調(diào)”。

所以,不是 Gateway “非要搞復(fù)雜”,而是為了性能不得不這么干。

3. Netty 是個(gè)什么東西?

你可以把 Netty 理解為一個(gè) 高性能網(wǎng)絡(luò)通信框架。它不依賴 Servlet 規(guī)范,直接跟操作系統(tǒng)底層的網(wǎng)絡(luò)接口打交道(比如 Linux 的 epoll)。

Tomcat 是“面向請(qǐng)求-響應(yīng)”的:來一個(gè) HTTP 請(qǐng)求 → 分配一個(gè)線程 → 處理 → 返回 → 線程釋放。

Netty 是“事件驅(qū)動(dòng)”的:所有連接注冊(cè)到 EventLoop(可以理解為一個(gè)線程池),當(dāng)有數(shù)據(jù)可讀/可寫時(shí),才觸發(fā)回調(diào)。一個(gè)線程能同時(shí)管成百上千個(gè)連接。

Spring Cloud Gateway 選擇 Netty,就是因?yàn)椋?/p>

  • 啟動(dòng)快
  • 內(nèi)存占用低
  • 支持長(zhǎng)連接、WebSocket、HTTP/2 等高級(jí)特性
  • 天然契合響應(yīng)式編程模型

打個(gè)比方:

  • Tomcat 像是“每個(gè)顧客配一個(gè)服務(wù)員”,人多了就忙不過來。
  • Netty 像是“一個(gè)服務(wù)員盯所有桌子,誰舉手就服務(wù)誰”,效率高得多。

當(dāng)然,Netty 學(xué)習(xí)曲線陡一點(diǎn),調(diào)試也麻煩些。但對(duì)網(wǎng)關(guān)這種 I/O 密集型場(chǎng)景,它是目前 Java 生態(tài)里最成熟的選擇。

總結(jié)一下

  • 不能在 Spring Cloud Gateway 中使用 Servlet Filter,因?yàn)樗慌茉?Servlet 容器上。
  • 要實(shí)現(xiàn)類似功能,請(qǐng)用 GlobalFilterGatewayFilter。
  • 別硬套舊習(xí)慣,響應(yīng)式編程有它自己的套路,適應(yīng)了其實(shí)也挺香。
  • 如果你只是做個(gè)后臺(tái)管理,QPS 幾十,用 Spring MVC + Tomcat 完全夠用,F(xiàn)ilter 寫起來也順手。
  • 但如果你要做 API 網(wǎng)關(guān),面對(duì)的是成千上萬的移動(dòng)端或第三方調(diào)用,那 Gateway + Netty + Reactor 這套組合拳,就是更合適的選擇。

我自己現(xiàn)在寫 Gateway 項(xiàng)目,已經(jīng)完全不用 Filter 這個(gè)詞了,一說“過濾器”,默認(rèn)就是指 GlobalFilter。思維轉(zhuǎn)過來之后,開發(fā)反而更清爽。

到此這篇關(guān)于Gateway 中能寫 Servlet Filter 嗎?的文章就介紹到這了,更多相關(guān)Gateway 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA運(yùn)行SpringBoot項(xiàng)目的超詳細(xì)步驟截圖

    IDEA運(yùn)行SpringBoot項(xiàng)目的超詳細(xì)步驟截圖

    在當(dāng)前的開發(fā)中Spring Boot開發(fā)框架已經(jīng)成為主流,下面這篇文章主要給大家介紹了關(guān)于IDEA運(yùn)行SpringBoot項(xiàng)目的超詳細(xì)步驟截圖,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Java如何實(shí)現(xiàn)簡(jiǎn)單后臺(tái)訪問并獲取IP

    Java如何實(shí)現(xiàn)簡(jiǎn)單后臺(tái)訪問并獲取IP

    這篇文章主要介紹了Java如何實(shí)現(xiàn)簡(jiǎn)單后臺(tái)訪問并獲取IP,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 如何基于Jenkins構(gòu)建Jmeter項(xiàng)目

    如何基于Jenkins構(gòu)建Jmeter項(xiàng)目

    這篇文章主要介紹了如何基于Jenkins構(gòu)建Jmeter項(xiàng)目,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java 生成PDF文檔的示例代碼

    Java 生成PDF文檔的示例代碼

    這篇文章主要介紹了Java 生成PDF文檔的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • Java集成swagger文檔組件

    Java集成swagger文檔組件

    這篇文章主要介紹了Java集成swagger文檔組件,通過詳細(xì)的圖文介紹和代碼分析展示,從頭展開說明詳細(xì)的過程,希望對(duì)你的開發(fā)有所幫助
    2021-06-06
  • IntelliJ IDEA設(shè)置Tabs實(shí)現(xiàn)同時(shí)打開多個(gè)文件且分行顯示

    IntelliJ IDEA設(shè)置Tabs實(shí)現(xiàn)同時(shí)打開多個(gè)文件且分行顯示

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA設(shè)置Tabs實(shí)現(xiàn)同時(shí)打開多個(gè)文件且分行顯示,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • 使用Gradle做Java代碼質(zhì)量檢查的方法示例

    使用Gradle做Java代碼質(zhì)量檢查的方法示例

    這篇文章主要介紹了使用Gradle做Java代碼質(zhì)量檢查的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03
  • SpringBoot整合Flink CDC實(shí)現(xiàn)實(shí)時(shí)追蹤mysql數(shù)據(jù)變動(dòng)

    SpringBoot整合Flink CDC實(shí)現(xiàn)實(shí)時(shí)追蹤mysql數(shù)據(jù)變動(dòng)

    我們將整合Spring Boot和Apache Flink CDC(Change Data Capture)來實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)追蹤,下面是一個(gè)基本的實(shí)踐流程代碼,包括搭建Spring Boot項(xiàng)目、整合Flink CDC以及實(shí)現(xiàn)數(shù)據(jù)變動(dòng)的實(shí)時(shí)追蹤,需要的朋友可以參考下
    2024-07-07
  • 關(guān)于Java限流功能的簡(jiǎn)單實(shí)現(xiàn)

    關(guān)于Java限流功能的簡(jiǎn)單實(shí)現(xiàn)

    這篇文章主要介紹了關(guān)于Java限流功能的簡(jiǎn)單實(shí)現(xiàn),在Java中,限流是一種常見的技術(shù)手段,用于控制系統(tǒng)的訪問速率,以保護(hù)系統(tǒng)免受過載和濫用,需要的朋友可以參考下
    2023-07-07
  • Mybatis批量插入大量數(shù)據(jù)的最優(yōu)方式總結(jié)

    Mybatis批量插入大量數(shù)據(jù)的最優(yōu)方式總結(jié)

    批量插入功能是我們?nèi)粘9ぷ髦斜容^常見的業(yè)務(wù)功能之一,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Mybatis批量插入大量數(shù)據(jù)的幾種最優(yōu)方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03

最新評(píng)論

调兵山市| 罗平县| 太仓市| 柯坪县| 大理市| 元氏县| 新晃| 崇明县| 辽源市| 上饶县| 江口县| 宁陵县| 巨野县| 普兰店市| 县级市| 新田县| 汽车| 泸定县| 汕尾市| 太仆寺旗| 仲巴县| 潼南县| 来安县| 东城区| 旬阳县| 沅江市| 新营市| 仁寿县| 门源| 隆昌县| 松滋市| 南宫市| 孟州市| 恭城| 利川市| 呼图壁县| 文登市| 宝兴县| 红原县| 耿马| 平南县|