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