最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Spring Cloud Gateway一次請求調(diào)用源碼解析

2023-03-21 10:12 作者:董嘉dongjia  | 我要投稿

一 前言

最近通過深入學(xué)習(xí)Spring Cloud Gateway發(fā)現(xiàn)這個框架的架構(gòu)設(shè)計非常簡單、有效,很多組件的設(shè)計都非常值得學(xué)習(xí),本文就Spring Cloud Gateway做一個簡單的介紹,以及針對一次請求Spring Cloud Gateway的處理流程做一個較為詳細的分析。

二 簡介

Spring Cloud Gateway 即Spring官方推出的一款A(yù)PI網(wǎng)關(guān),該框架包含了Spring5、SpringBoot2、Project Reactor,其中底層通信框架用的netty。Spring Cloud Gateway在推出之初的時候,Netflix公司已經(jīng)推出了類似功能的API網(wǎng)關(guān)框架ZUUL,但ZUUL有一個缺點是通信方式是阻塞的,雖然后來升級到了非阻塞式的ZUUL2,但是由于Spring Cloud Gateway已經(jīng)推出一段時間,同時自身也面臨資料少、維護性較差的因素沒有被廣泛應(yīng)用。

1 關(guān)鍵術(shù)語

在使用Spring Cloud Gateway的時候需要理解三個模塊,即

Route:

即一套路由規(guī)則,是集URI、predicate、filter等屬性的一個元數(shù)據(jù)類。

Predicate:

這是Java8函數(shù)式編程的一個方法,這里可以看做是滿足什么條件的時候,route規(guī)則進行生效。

Filter:

filter可以認為是Spring Cloud Gateway最核心的模塊,熔斷、安全、邏輯執(zhí)行、網(wǎng)絡(luò)調(diào)用都是filter來完成的,其中又細分為gateway filter和global filter,區(qū)別在于是具體一個route規(guī)則生效還是所有route規(guī)則都生效。

可以先上一段代碼來看看:

@RequestMapping("/paramTest") ?public Object paramTest(@RequestParam Map<String,Object> param) { ? ? ?return param.get("name"); ?} ?@Bean ?public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes() ? ? ?.route("path_route", r -> ? ? ? ? ? ? ? ? ? r.path("/get") ? ? ? ? ? ? ? ? ?.filters(f -> f.addRequestParameter("name", "value")) ? ? ? ? ? ? ? ? ?.uri("forward:///paramTest")) ? ? ?.build(); ?}

  • route方法代表的就是一個路由規(guī)則;

  • path方法代表的就是一個predicate,背后的現(xiàn)實是PathRoutePredicateFactory,在這段代碼的含義即當(dāng)路徑包含/get的時候,當(dāng)前規(guī)則生效。

  • filters方法的意思即給當(dāng)前路由規(guī)則添加一個增加請求參數(shù)的filter,每次請求都對參數(shù)里添加 name:value 的鍵值對;

  • uri 方法的含義即最終路由到哪里去,這里的forward前綴會將請求交給spring mvc的DispatcherHandler進行路由,進行本機的邏輯調(diào)用,除了forward以外還可以使用http、https前綴進行http調(diào)用,lb前綴可以在配置注冊中心后進行rpc調(diào)用。


上圖是Spring Cloud Gateway官方文檔給出的一個工作原理圖,Spring Cloud Gateway 接收到請求后進行路由規(guī)則的匹配,然后交給web handler 進行處理,web handler 會執(zhí)行一系列的filter邏輯。

三 流程分析

1 接受請求

Spring Cloud Gateway的底層框架是netty,接受請求的關(guān)鍵類是ReactorHttpHandlerAdapter,做的事情很簡單,就是將netty的請求、響應(yīng)轉(zhuǎn)為http的請求、響應(yīng)并交給一個http handler執(zhí)行后面的邏輯,下圖為該類的源碼僅保留核心邏輯。

? ?@Override ? ?public Mono< Void> apply(HttpServerRequest request, HttpServerResponse response) { ? ? ? ?NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.alloc()); ? ? ? ?ServerHttpRequest adaptedRequest; ? ? ? ?ServerHttpResponse adaptedResponse; ? ?//轉(zhuǎn)換請求 ? ? ? ?try { ? ? ? ? ? ?adaptedRequest = new ReactorServerHttpRequest(request, bufferFactory); ? ? ? ? ? ?adaptedResponse = new ReactorServerHttpResponse(response, bufferFactory); ? ? ? ?} ? ? ? ?catch (URISyntaxException ex) { ? ? ? ? ? ?if (logger.isWarnEnabled()) { ? ? ? ? ? ?... ? ? ? ?} ? ? ? ?... ? ? ? ?return this.httpHandler.handle(adaptedRequest, adaptedResponse) ? ? ? ? ? ? ? ?.doOnError(ex -> logger.warn("Handling completed with error: " + ex.getMessage())) ? ? ? ? ? ? ? ?.doOnSuccess(aVoid -> logger.debug("Handling completed with success")); ? ?}

2 WEB過濾器鏈

http handler做的事情第一是將request 和 response轉(zhuǎn)為一個exchange,這個exchange非常核心,是各個filter之間參數(shù)流轉(zhuǎn)的載體,該類包含request、response、attributes(擴展字段),接著做的事情就是web filter鏈的執(zhí)行,其中的邏輯主要是監(jiān)控。


其中WebfilterChainParoxy 又會引出新的一條filter鏈,主要是安全、日志、認證相關(guān)的邏輯,由此可見Spring Cloud Gateway的過濾器設(shè)計是層層嵌套,擴展性很強。


3 尋找路由規(guī)則

核心類是
RoutePredicateHandlerMapping,邏輯也非常簡單,就是把所有的route規(guī)則的predicate遍歷一遍看哪個predicate能夠命中,核心代碼是:

return this.routeLocator.getRoutes() ? ? ?.filter(route -> { ? ? ? ? ... ? ? ? ? return route.getPredicate().test(exchange); ? ? ?})

因為我這里用的是path進行過濾,所以背后的邏輯是PathRoutePredicateFactory來完成的,除了PathRoutePredicateFactory還有很多predicate規(guī)則。


這些路由規(guī)則都能從官方文檔上找到影子。


4 核心過濾器鏈執(zhí)行

找到路由規(guī)則后下一步就是執(zhí)行了,這里的核心類是FilteringWebHandler,其中的源碼為:


做的事情很簡單:

  1. 獲取route級別的過濾器

  2. 獲取全局過濾器

  3. 兩種過濾器放在一起并根據(jù)order進行排序

  4. 執(zhí)行過濾器鏈


因為我的配置里包含了一個添加請求參數(shù)的邏輯,所以紅線箭頭處就是我配置的gateway filter名為
AddRequestParameterGatewayFilterFactory,其余全是Gloabl Filter,這些過濾器的功能主要是url解析,請求轉(zhuǎn)發(fā),響應(yīng)回寫等邏輯,因為我們這里用的是forward schema,所以請求轉(zhuǎn)發(fā)會由ForwardRoutingFilter進行執(zhí)行。

5 請求轉(zhuǎn)發(fā)

ForwardRoutingFilter做的事情也很簡單,直接復(fù)用了spring mvc的能力,將請求提交給dispatcherHandler進行處理,dispatcherHandler會根據(jù)path前綴找到需要目標處理器執(zhí)行邏輯。

@Overridepublic Mono< Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ? URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); ? String scheme = requestUrl.getScheme(); ? if (isAlreadyRouted(exchange) || !"forward".equals(scheme)) { ? ? ?return chain.filter(exchange); ? } ? setAlreadyRouted(exchange); ? //TODO: translate url? ? if (log.isTraceEnabled()) { ? ? ?log.trace("Forwarding to URI: "+requestUrl); ? } ? return this.dispatcherHandler.handle(exchange); }

6 響應(yīng)回寫

響應(yīng)回寫的核心類是NettyWriteResponseFilter,但是大家可以注意到執(zhí)行器鏈中NettyWriteResponseFilter的排序是在最前面的,按道理這種響應(yīng)處理的類應(yīng)該是在靠后才對,這里的設(shè)計比較巧妙。大家可以看到chain.filter(exchange).then(),意思就是執(zhí)行到我的時候直接跳過下一個,等后面的過濾器都執(zhí)行完后才執(zhí)行這段邏輯,這種行為控制的方法值得學(xué)習(xí)。

@Overridepublic Mono< Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ? // NOTICE: nothing in "pre" filter stage as CLIENT_RESPONSE_ATTR is not added ? // until the WebHandler is run ? return chain.filter(exchange).then(Mono.defer(() -> { ? ? ?HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR); ? ? ?if (clientResponse == null) { ? ? ? ? return Mono.empty(); ? ? ?} ? ? ?log.trace("NettyWriteResponseFilter start"); ? ? ?ServerHttpResponse response = exchange.getResponse(); ? ? ?NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory(); ? ? ?//TODO: what if it's not netty ? ? ?final Flux< NettyDataBuffer> body = clientResponse.receive() ? ? ? ? ? ?.retain() //TODO: needed? ? ? ? ? ? ?.map(factory::wrap); ? ? ?MediaType contentType = response.getHeaders().getContentType(); ? ? ?return (isStreamingMediaType(contentType) ? ? ? ? ? ? ?response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body)); ? })); }

四 總結(jié)

整體讀完Spring Cloud Gateway請求流程代碼后,有幾點感受:

  1. 過濾器是Spring Cloud Gateway最核心的設(shè)計,甚至于可以夸張說Spring Cloud Gateway是一個過濾器鏈執(zhí)行框架而不是一個API網(wǎng)關(guān),因為API網(wǎng)關(guān)實際的請求轉(zhuǎn)發(fā)、請求響應(yīng)回寫都是在過濾器中做的,這些是Spring Cloud Gateway感知不到的邏輯。

  2. Spring Cloud Gateway路由規(guī)則獲取的模塊具備優(yōu)化的空間,因為是循環(huán)遍歷進行獲取的,如果每個route規(guī)則較多,predicate規(guī)則較復(fù)雜,就可以考慮用map進行優(yōu)化了,當(dāng)日route規(guī)則,predicate規(guī)則也不會很復(fù)雜,兼顧到代碼的可讀性,當(dāng)前方式也沒有什么問題。

  3. 作為API網(wǎng)關(guān)框架,內(nèi)置了非常多的過濾器,如果有過濾器的卸載功能可能會更好,用戶可用根據(jù)實際情況卸載不必要的功能,背后減少的邏輯開銷,在調(diào)用量極大的API網(wǎng)關(guān)場景,收益也會很可觀。


Spring Cloud Gateway一次請求調(diào)用源碼解析的評論 (共 條)

分享到微博請遵守國家法律
宁都县| 保德县| 遂平县| 灵山县| 新干县| 乌拉特中旗| 宁津县| 泸水县| 攀枝花市| 忻州市| 新营市| 项城市| 女性| 嘉义县| 顺昌县| 托克托县| 兴安盟| 仪陇县| 营山县| 青神县| 布尔津县| 临沂市| 互助| 彭州市| 莒南县| 高阳县| 鸡西市| 武功县| 定陶县| 麻江县| 全州县| 新巴尔虎左旗| 开远市| 会东县| 江安县| 宣汉县| 通海县| 建德市| 象山县| 阿荣旗| 蓬安县|