Spring Cloud Gateway Filter 執(zhí)行原理刨析

準(zhǔn)備工作

需要了解響應(yīng)式編程才睹,推薦閱讀

版本

Spring Cloud Gateway:2.2.3.RELEASE

本文目標(biāo)

了解 Gateway Filter 內(nèi)部執(zhí)行原理

問題:

@Component
public class TestGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("start");
        Mono<Void> mono = chain.filter(exchange);
        log.info("end")
        return mono;
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

我編寫了一個 TestGlobalFilter瞭空,下一個 Filter 的邏輯是輸出日志 HelloWorld。日志中輸出的順序會是什么樣伟骨?

正確答案是

start
end
HelloWorld

如果按照 Servlet 的開發(fā)思想,調(diào)用 chain.filter 一定會立刻執(zhí)行下一個 Filter撵摆,Gateway 為什么不可以呢底靠?

因?yàn)?chain.filter 的返回值是 Mono,必須要有訂閱者調(diào)用 subscribe 后才會執(zhí)行發(fā)布者邏輯

DefaultGatewayFilterChain

我們來看下 DefaultGatewayFilterChain 的代碼

DefaultGatewayFilterChain

DefaultGatewayFilterChain 返回的是一個 MonoDefer特铝。其內(nèi)部包含了調(diào)用下一個 Filter 的內(nèi)部函數(shù)暑中,那么這個邏輯怎樣才能觸發(fā)的呢?下面繼續(xù)來看 MonoDefer 的源碼

MonoDefer

MonoDefer

MonoDefer subscribe 邏輯如下

  • 調(diào)用 supplier.get()鲫剿,執(zhí)行內(nèi)部函數(shù)的命令式代碼鳄逾,執(zhí)行結(jié)束后,內(nèi)部函數(shù)會返回一個 Mono
  • p.subscribe(actual); 訂閱內(nèi)部函數(shù)返回的 Mono

當(dāng) supplier.get() 拋出異常時(shí)灵莲,首先向訂閱者傳遞一個空的 Subscription雕凹,然后再傳遞異常

Operators.error

MonoDefer 雖然也是發(fā)布者,但是他只是在真正的發(fā)布者和訂閱者之間做一個承載的作用

過濾器鏈刨析

在理解了上述兩個類之后,我們現(xiàn)在可以梳理一下 Gateway 過濾器鏈的執(zhí)行邏輯了

雖然從 Gateway 接收到請求到過濾器鏈中間還會經(jīng)歷很多步驟枚抵,這里我們?yōu)榱朔奖憷斫庀哂苯影堰^濾器鏈的調(diào)用方,抽象為一個訂閱者(因?yàn)樽罱K過濾器鏈會返回一個 Publisher)

除此之外汽摹,再簡化一下 Filter 的返回值李丰。正常來說 Filter 可以返回任何響應(yīng)式的發(fā)布者邏輯,我們這里簡化為每個 Filter 都返回 chain.filter (將最簡單的流程理解后逼泣,其實(shí)復(fù)雜的響應(yīng)式返回也是大同小異)

  1. 訂閱者請求 First Filter趴泌,這里首先會執(zhí)行 filter 方法中所有的命令式的代碼(響應(yīng)式的代碼并不會執(zhí)行,因?yàn)?Mono 并沒有被消費(fèi))

  2. 訂閱者調(diào)用 Filter 返回的 MonoDefer 的 subscribe 方法拉庶。MonoDefer 被訂閱時(shí)首先會執(zhí)行內(nèi)部函數(shù)嗜憔。如果還有下一個過濾器,則執(zhí)行并返回 nextFilter.filter氏仗,如果所有過濾器都已執(zhí)行完畢則返回 Mono.empty(對應(yīng) MonoDefer 的 44 行)

  3. nextFilter.filter 先執(zhí)行 filter 方法中所有的命令式的代碼吉捶,然后返回 chain.filter

  4. First Filter 返回的 MonoDefer 內(nèi)部會去訂閱 nextFilter.filter 返回的 Mono(對應(yīng) MonoDefer 的 52 行)。Second MonoDefer(nextFilter.filter 的返回值)被訂閱廓鞠,接下來就是重復(fù)步驟 2 的邏輯帚稠,無限套娃下去直到所有 Filter 執(zhí)行完畢...

下面用一張圖來解釋一下上面的邏輯

通過上述的圖文講解,我們可以看到響應(yīng)式編程中一個過濾器鏈該怎么設(shè)計(jì)和實(shí)現(xiàn)

回到問題

回到最開始的問題床佳,如果想在 Spring Cloud Gateway 中實(shí)現(xiàn)先執(zhí)行過濾器鏈再執(zhí)行某某操作滋早,應(yīng)該怎么寫呢?

@Slf4j
@Component
public class LogFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("hello");
        return chain.filter(exchange)
                .then(Mono.defer(() -> {
                    log.info("world");
                    return Mono.empty();
                }));
    }

    @Override
    public int getOrder() {
        return -9;
    }
}

Mono.then 的作用就是內(nèi)部消費(fèi)并忽略第一個 Mono(但是 Error 信號會被傳遞下去)砌们,然后入?yún)⒌?Mono 作為生產(chǎn)者向下游傳播數(shù)據(jù)杆麸。

忽略了 chain.filter 返回的 Mono 不會造成問題嗎?當(dāng)然不會浪感,Gateway 的 Filter 鏈的訂閱者并不需要我們傳遞什么數(shù)據(jù)昔头,我們只需要將所有過濾器代碼執(zhí)行完即可

最后

如果覺得我的文章對你有幫助,動動小手點(diǎn)下喜歡和關(guān)注影兽,你的支持是對我最大的幫助

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揭斧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子峻堰,更是在濱河造成了極大的恐慌讹开,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捐名,死亡現(xiàn)場離奇詭異旦万,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)镶蹋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門成艘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赏半,“玉大人,你說我怎么就攤上這事淆两《象铮” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵琼腔,是天一觀的道長瑰枫。 經(jīng)常有香客問我踱葛,道長丹莲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任尸诽,我火速辦了婚禮甥材,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘性含。我一直安慰自己洲赵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布商蕴。 她就那樣靜靜地躺著叠萍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绪商。 梳的紋絲不亂的頭發(fā)上苛谷,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音格郁,去河邊找鬼腹殿。 笑死,一個胖子當(dāng)著我的面吹牛例书,可吹牛的內(nèi)容都是我干的锣尉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼决采,長吁一口氣:“原來是場噩夢啊……” “哼自沧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起树瞭,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤拇厢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后移迫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旺嬉,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年厨埋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了邪媳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖雨效,靈堂內(nèi)的尸體忽然破棺而出迅涮,到底是詐尸還是另有隱情,我是刑警寧澤徽龟,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布叮姑,位于F島的核電站,受9級特大地震影響据悔,放射性物質(zhì)發(fā)生泄漏传透。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一极颓、第九天 我趴在偏房一處隱蔽的房頂上張望朱盐。 院中可真熱鬧,春花似錦菠隆、人聲如沸兵琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躯肌。三九已至,卻和暖如春破衔,著一層夾襖步出監(jiān)牢的瞬間清女,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工运敢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留校仑,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓传惠,卻偏偏與公主長得像迄沫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卦方,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容