本文將詳細(xì)分析SpringCloud Gateway是如何實(shí)現(xiàn)的。
架構(gòu)
SpringCloud Gateway(下面簡稱SG)基于SpringWebFlux,整體架構(gòu)如下圖所示:

SG定義了幾個(gè)概念:
- 路由(Route):路由是網(wǎng)關(guān)的基本構(gòu)成單元。它由一個(gè)ID、一個(gè)目標(biāo)URL、一組謂詞以及一組過濾器組成。當(dāng)謂詞判定為true時(shí),表示請求與對應(yīng)路由匹配
- 謂詞(Predicate):JAVA8函數(shù)式謂詞。輸入?yún)?shù)是Spring框架封裝的ServerWebExchange對象。開發(fā)人員可以基于此對象來匹配HTTP請求的任意內(nèi)容,比如請求頭或請求參數(shù)
- 過濾器(Filter):由特定工廠類構(gòu)造的一組Spring框架提供的GatewayFilter對象。過濾器可以在請求或響應(yīng)被處理前/后對其進(jìn)行修改。
架構(gòu)流程
一個(gè)請求被SG處理的大致流程如下所示:
- GatewayHandlerMApping判定對應(yīng)的請求是否匹配某個(gè)路由。
- 如果匹配到某個(gè)路由,則將請求交給GatewayWebHandler處理,Handler調(diào)用一個(gè)Filter鏈來處理這個(gè)請求:
- 首先,會(huì)執(zhí)行「pre」過濾器的邏輯
- 然后執(zhí)行請求處理luoji
- 最后再執(zhí)行「post」過濾器的邏輯
- 如果沒有匹配到路由,則不執(zhí)行對應(yīng)處理
下面以一個(gè)具體的例子來進(jìn)行說明。
SG支持基于Java編碼方式的配置以及基于配置文件的配置。
- Java編碼方式配置

- 配置文件配置

這兩個(gè)配置是等價(jià)的。
啟動(dòng)流程
- SG是基于SpringBoot構(gòu)建的,啟動(dòng)相關(guān)配置可見項(xiàng)目中的spring.factories文件。
- 由于涉及的配置很多,我們直接定位到核心Bean
- HandlerMapping:SG構(gòu)建的HandlerMapping實(shí)例是RoutePredicatehandlerMapping
- WebHandler:構(gòu)建的WebHandler為FilteringWebHandler,它接收List<GlobalFilter>作為參數(shù)
- Route:路由構(gòu)建由RouteDefinitionRouteLocator實(shí)例來處理,它基于路由配置(即上面的配置文件)來構(gòu)建Route實(shí)例

- 從上面的代碼可以看到,最終Filter,WebHandler(注意,這里是GlobalFilter),Route都作為直接參數(shù)或間接參數(shù)傳遞給了RoutePredicateHandlerMapping。所以我們可以從RoutePredicateHandlerMapping來梳理SG的執(zhí)行流程。
RoutePredicateHandlerMapping是HandlerMapping的一個(gè)實(shí)例,HandlerMapping歸屬于SpringWebFlux,這里不做說明,請自行查閱相關(guān)資料。

請求處理流程
我們結(jié)合上面的配置文件,以及SG具體的實(shí)例來說明SG對請求的處理流程:
- 當(dāng)請求到達(dá)SG后,首先由RoutePredicateHandlerMapping來處理請求(前面的流程由SpringWebFlux處理,不在討論范圍內(nèi))
- 首先根據(jù)請求從RouteLocator中查詢符合規(guī)則的路由,返回Route
- 返回的Route設(shè)置為exchange的屬性
- 返回構(gòu)造時(shí)傳入的WebHandler
- 執(zhí)行WebHandler
- 從exchange的屬性中獲取Route
- 從Route中獲取GatewayFilter鏈
- 與GlobalFilter進(jìn)行整合,排序,構(gòu)成完成的Filter
- 遍歷執(zhí)行Filter
- 其中部分GlobalFilter有執(zhí)行Service的功能,例如NettyRoutingFilter。這類Filter負(fù)責(zé)將請求轉(zhuǎn)發(fā)給對應(yīng)的Service進(jìn)行具體的邏輯處理

關(guān)鍵流程代碼

- 1處即根據(jù)exchange從RouteLocator中查詢匹配的路由
- 1.1處根據(jù)謂詞進(jìn)行路由匹配
- 2處,將路由設(shè)置到exchange的屬性中
- 3處,從exchange的屬性中獲取路由
- 4處,從路由中獲取GatewayFilter列表
- 5、6、7處,將GlobalFilter與GatewayFilter整合到一起,按Order排序
- 8處,執(zhí)行Filter
執(zhí)行服務(wù)
SG中服務(wù)的執(zhí)行也是通過GlobalFilter來執(zhí)行的,SG中默認(rèn)配置了一些GlobalFilter,下面列出了部分。

具體Filter作用這里不做詳述,可自行閱讀源碼,這里只關(guān)注三個(gè)Filter:
- LoadBalancerClientFilter:負(fù)載均衡
- NettyRoutingFilter:執(zhí)行服務(wù)
- NettyWriteResponseFilter:回寫響應(yīng)
先看LoadBalancerClientFilter,核心源碼如下:

- 1處,如果配置的目標(biāo)url不是lb開頭的,則忽略。即對lb://格式的url進(jìn)行負(fù)載均衡處理
- 2處,根據(jù)exchange選擇對應(yīng)的Service,這里實(shí)現(xiàn)了負(fù)載均衡邏輯,具體自行閱讀源碼
- 3處,構(gòu)建真實(shí)的Service請求地址
- 4處,將請求設(shè)置到exchange的屬性中
NettyRoutingFilter在LoadBalancerClientFilter之后,用于執(zhí)行服務(wù)。

- 1處,從exchange中獲取服務(wù)請求
- 2處,構(gòu)建請求參數(shù),包括method,url和chunkedTransfer(代碼略)
- 3處,通過httpClient發(fā)送請求調(diào)用
- 4處,將響應(yīng)和連接信息設(shè)置到了exchange屬性中
最后由NettyWriteResponseFilter來處理響應(yīng)。

- 1處,首先注意到,這個(gè)Filter是個(gè)post過濾器,即是來處理響應(yīng)的
- 2處,從exchange中獲取Connection
- 3處,從連接獲取服務(wù)響應(yīng)
- 4處,將服務(wù)響應(yīng)寫入到網(wǎng)關(guān)響應(yīng)中
參考資料
- SpringCloud Gateway官方文檔
- SpringCloud Gateway 源碼