本文將詳細分析SpringCloud Gateway是如何實現的。
架構
SpringCloud Gateway(下面簡稱SG)基于SpringWebFlux,整體架構如下圖所示:
SG定義了幾個概念:
- 路由(Route):路由是網關的基本構成單元。它由一個ID、一個目標URL、一組謂詞以及一組過濾器組成。當謂詞判定為true時,表示請求與對應路由匹配
- 謂詞(Predicate):JAVA8函數式謂詞。輸入參數是Spring框架封裝的ServerWebExchange對象。開發人員可以基于此對象來匹配HTTP請求的任意內容,比如請求頭或請求參數
- 過濾器(Filter):由特定工廠類構造的一組Spring框架提供的GatewayFilter對象。過濾器可以在請求或響應被處理前/后對其進行修改。
架構流程
一個請求被SG處理的大致流程如下所示:
- GatewayHandlerMApping判定對應的請求是否匹配某個路由。
- 如果匹配到某個路由,則將請求交給GatewayWebHandler處理,Handler調用一個Filter鏈來處理這個請求:
- 首先,會執行「pre」過濾器的邏輯
- 然后執行請求處理luoji
- 最后再執行「post」過濾器的邏輯
- 如果沒有匹配到路由,則不執行對應處理
下面以一個具體的例子來進行說明。
SG支持基于Java編碼方式的配置以及基于配置文件的配置。
- Java編碼方式配置
- 配置文件配置
這兩個配置是等價的。
啟動流程
- SG是基于SpringBoot構建的,啟動相關配置可見項目中的spring.factories文件。
- 由于涉及的配置很多,我們直接定位到核心Bean
- HandlerMapping:SG構建的HandlerMapping實例是RoutePredicatehandlerMapping
- WebHandler:構建的WebHandler為FilteringWebHandler,它接收List<GlobalFilter>作為參數
- Route:路由構建由RouteDefinitionRouteLocator實例來處理,它基于路由配置(即上面的配置文件)來構建Route實例
- 從上面的代碼可以看到,最終Filter,WebHandler(注意,這里是GlobalFilter),Route都作為直接參數或間接參數傳遞給了RoutePredicateHandlerMapping。所以我們可以從RoutePredicateHandlerMapping來梳理SG的執行流程。
RoutePredicateHandlerMapping是HandlerMapping的一個實例,HandlerMapping歸屬于SpringWebFlux,這里不做說明,請自行查閱相關資料。
請求處理流程
我們結合上面的配置文件,以及SG具體的實例來說明SG對請求的處理流程:
- 當請求到達SG后,首先由RoutePredicateHandlerMapping來處理請求(前面的流程由SpringWebFlux處理,不在討論范圍內)
- 首先根據請求從RouteLocator中查詢符合規則的路由,返回Route
- 返回的Route設置為exchange的屬性
- 返回構造時傳入的WebHandler
- 執行WebHandler
- 從exchange的屬性中獲取Route
- 從Route中獲取GatewayFilter鏈
- 與GlobalFilter進行整合,排序,構成完成的Filter
- 遍歷執行Filter
- 其中部分GlobalFilter有執行Service的功能,例如NettyRoutingFilter。這類Filter負責將請求轉發給對應的Service進行具體的邏輯處理
關鍵流程代碼
- 1處即根據exchange從RouteLocator中查詢匹配的路由
- 1.1處根據謂詞進行路由匹配
- 2處,將路由設置到exchange的屬性中
- 3處,從exchange的屬性中獲取路由
- 4處,從路由中獲取GatewayFilter列表
- 5、6、7處,將GlobalFilter與GatewayFilter整合到一起,按Order排序
- 8處,執行Filter
執行服務
SG中服務的執行也是通過GlobalFilter來執行的,SG中默認配置了一些GlobalFilter,下面列出了部分。
具體Filter作用這里不做詳述,可自行閱讀源碼,這里只關注三個Filter:
- LoadBalancerClientFilter:負載均衡
- NettyRoutingFilter:執行服務
- NettyWriteResponseFilter:回寫響應
先看LoadBalancerClientFilter,核心源碼如下:
- 1處,如果配置的目標url不是lb開頭的,則忽略。即對lb://格式的url進行負載均衡處理
- 2處,根據exchange選擇對應的Service,這里實現了負載均衡邏輯,具體自行閱讀源碼
- 3處,構建真實的Service請求地址
- 4處,將請求設置到exchange的屬性中
NettyRoutingFilter在LoadBalancerClientFilter之后,用于執行服務。
- 1處,從exchange中獲取服務請求
- 2處,構建請求參數,包括method,url和chunkedTransfer(代碼略)
- 3處,通過httpClient發送請求調用
- 4處,將響應和連接信息設置到了exchange屬性中
最后由NettyWriteResponseFilter來處理響應。
- 1處,首先注意到,這個Filter是個post過濾器,即是來處理響應的
- 2處,從exchange中獲取Connection
- 3處,從連接獲取服務響應
- 4處,將服務響應寫入到網關響應中
參考資料
- SpringCloud Gateway官方文檔
- SpringCloud Gateway 源碼