作者 | 波哥
審校 | 重樓
Spring Cloud Gateway是一個基于Spring Framework 5和Project Reactor的響應式API網關,旨在為構建分布式微服務架構提供高性能和靈活的路由機制。底層實現基于Spring WebFlux框架,它使用WebFlux的HandlerMapping和HandlerAdapter來處理請求和生成響應;使用了反應式編程的思想,基于Project Reactor庫實現異步、非阻塞的事件驅動架構,以提高性能和吞吐量。
本文將帶你深入spring Cloud Gateway的底層實現原理,重點關注其核心組件和代碼實現。
1. Spring Cloud Gateway核心組件
Spring Cloud Gateway的核心組件主要有:
- Routes(路由):定義了URI、謂詞(Predicates)和過濾器(Filters)的規則,用于將請求映射到后端服務。
- Predicates(謂詞):定義了匹配條件,用于決定請求是否應該映射到該路由。
- Filters(過濾器):用于在請求和響應期間對請求和響應進行修改或轉換。在調用過程中,會有多個過濾器形成過濾器鏈,用于處理請求、修改請求頭、記錄日志、限流等操作。
2.SpringCloud Gateway的具體使用
先來了解下Spring Cloud Gateway的具體使用過程,包括定義路由規則、自定義過濾器、啟動應用等步驟。讓我們逐步詳細介紹這些步驟。
- 定義路由規則
首先,在Spring Cloud Gateway中,我們需要定義路由規則。路由規則定義了請求該如何被路由到后端服務。這些規則通常以Java或YAML配置文件的形式提供,以YAML配置為例:
- 自定義過濾器
我們可以編寫自定義過濾器,對請求或響應進行特定的處理,例如添加頭信息、修改請求、記錄日志等。這里定義了要給GlobalFilter類型的過濾器,當然也可以定義非GlobalFilter類型的過濾器。
- 啟動應用
通過啟動Spring Boot應用程序,Spring Cloud Gateway將開始監聽配置的端口,并根據路由規則將請求轉發到相應的后端服務。
- 訪問API
現在您可以通過訪問定義的路由規則來測試API。
例如,對于上述路由規則的Java配置方式,可以使用以下URL訪問API:
http://localhost:8080/sample/some-endpoint
Spring Cloud Gateway將根據路由規則將請求轉發到http://example.com。
3.代碼原理剖析
接下來,我們從上述使用案例入手,從GateWay的源碼層面分析其底層實現原理。要理解其原理,其實只要理解如下這張圖就足夠了,所以接下來的分析我們將圍繞這張圖展開講解。
Gateway作為網關,也就是統一的入口,它本身也是一個Web應用,在上面我們說過它是WebFlux框架,WebFlux大部分朋友可能都沒接觸過,我們可以使用SpringMVC進行類比。從上圖我們可以看出,當請求到達Gateway后,首先會進入DispatcherHandler.handle方法進行處理,在該方法中調用GatewayHandlerMapping.getHandler方法,然后進入GatewayWebHandler.handle方法,隨后進入Filter鏈進行處理,處理完成后調用具體的服務。綜上,在整個的調用過程中使用到:DispatcherHandler、RoutePredicateHandlerMapping、SimpleHandlerAdapter、FilteringWebHandler幾個核心的類(當然還使用到了Ribbon負載均衡、Netty/Nacos等注冊中心相關的核心代碼,不過本篇我們只分析Gateway相關源碼),接下來我們將詳細分析關鍵代碼。
1.DispatcherHandler
該類做為Gateway的入口,接受所有網關的請求,類似于SpringMVC的DispatcherServlet類,所有的請求都將進入到handle方法中:
2.RoutePredicateHandlerMapping
這個RoutePredicateHandlerMapping就是上述handlerMappings的具體實現類,在handle方法就會使用到該類的實例,該類的主要作用是獲取Route,也就是我們在配置文件中可能會配置多個Route,對于當前請求最終會使用哪個Route。
很多朋友會問:HandlerMappings有那么多實現類,你怎么知道會使用RoutePredicateHandlerMapping呢?
要回答這個問題,得對SpringBoot的底層實現有一定的了解,針對SpringBoot的底層實現大家可以看相關的文章,這里不做分析,在這里大家只需要尋找到
的spring.factories文件,SpringBoot會讀取該文件中的配置,并將這些配置交由Spring容器管理就可以了。
在該配置中有一個配置類:GatewayAutoConfiguration,該配置類中完成對RoutePredicateHandlerMapping、FilteringWebHandler等的配置:
RoutePredicateHandlerMapping做為HandlerMapping的實現類,自然就會被調用到。
接下來我們看RoutePredicateHandlerMapping是如何幫我們尋找到Route的:
如上圖代碼所示,就是在lookupRoute方法中通過調用routeLocator.getRoutes方法獲取到所有我們在應用配置文件中配置的Route(具體如何獲取所有的Route源碼比較簡單,就是讀取配置文件中的所有Route配置信息,這個大家可以自行去看下代碼),然后調用getPredicate().apply方法確定具體的Route(也就是匹配斷言),匹配成功后,會將該Route設置到exchange(可以理解為當前請求,即Request)的屬性中:
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
3.SimpleHandlerAdapter
上述獲取到Route后,接下來會進入到DispatcherHandler.invokeHandler方法:
該方法會執行SimpleHandlerAdapter的handle方法:
該方法調用WebHandler.handle方法,也就是FilteringWebHandler。
4.FilteringWebHandler
進入FilteringWebHandler.handle方法后,會從exchange上下文中得到Route,一個Route中可能有多個GatewayFilter,這里將多個GatewayFilter生成一個DefaultGatewayFilterChain鏈對象,然后啟動鏈調用,這過程中會完成一些列的動作,比如整合Ribbon負載均衡獲取到服務實例(ServerInstantce),最終調用NettyRoutingFilter完成對服務的調用。如下是Spring Cloud Gateway框架內置的GlobalFilter:
全局過濾器 | 作用 |
Forward Routing Filter | 用于本地forward,也就是將請求在Gateway服務內進行轉發,而不是轉發到下游服務 |
LoadBalancerClient Filter | 整合Ribbon實現負載均衡,得到最終的ServerInstance |
Netty Routing Filter | 使用Netty的HttpClient轉發http、https請求 |
Netty Write Response Filter | 將代理響應寫回網關的客戶端側 |
RouteToRequestUrl Filter | 將從request里獲取的原始url轉換成Gateway進行請求轉發時所使用的url |
Websocket Routing Filter | 使用Spring Web Socket將轉發 Websocket 請求 |
Gateway Metrics Filter | 整合監控相關,提供監控指標 |
本篇對Gateway的底層實現原理進行詳細介紹,希望能對讀者朋友們有所幫助。
作者介紹
波哥,互聯行業從業10余年,先后擔任項目總監及架構師。目前專攻技術,喜歡研究技術原理。技術全面,主攻Java,精通JVM底層機制及Spring全家桶底層框架原理,熟練掌握當前主流的中間件、服務網格等技術原理。