摘要:添加相關(guān)依賴之后,會有這個。接著,根據(jù)的源碼分析,會繼續(xù)鏈路,到達下一個,即。在中,我們會計算出路由并發(fā)送請求到符合條件的。這個是的,會讀取配置并生成路由。
我們繼續(xù)分析上一節(jié)提到的 WebHandler
。加入 Spring Cloud Sleuth 以及 Prometheus 相關(guān)依賴之后, Spring Cloud Gateway 的處理流程如下所示:
Spring Cloud Gateway 是基于 Spring WebFlux 開發(fā)的異步響應(yīng)式網(wǎng)關(guān),異步響應(yīng)式代碼比較難以理解和閱讀,我這里給大家分享一種方法去理解,通過這個流程來理解 Spring Cloud Gateway 的工作流程以及底層原理。其實可以理解為,上圖這個流程,就是拼出來一個完整的 Mono(或者 Flux)流,最后 subscribe 執(zhí)行。
當收到一個請求的時候,會經(jīng)過 org.springframework.web.server.handler.DefaultWebFilterChain
,這是 WebFilter 的調(diào)用鏈,這個鏈路包括三個 WebFilter:
org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter
:添加 Prometheus 相關(guān)依賴之后,會有這個 MetricsWebFilter,用于記錄請求處理耗時,采集相關(guān)指標。org.springframework.cloud.sleuth.instrument.web.TraceWebFilter
:添加 Spring Cloud Sleuth 相關(guān)依賴之后,會有這個 TraceWebFilter。org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter
:Spring Cloud Gateway 路由權(quán)重相關(guān)配置功能相關(guān)實現(xiàn)類,這個我們這里不關(guān)心。在這個 DefaultWebFilterChain
會形成這樣一個 Mono,我們依次將他們標記出來,首先是入口代碼 org.springframework.web.server.handler.DefaultWebFilterChain#filter
:
public Mono filter(ServerWebExchange exchange) { return Mono.defer(() -> // this.currentFilter != null 代表 WebFilter 鏈還沒有結(jié)束 // this.chain != null 代表 WebFilter 鏈不為空 this.currentFilter != null && this.chain != null ? //在 WebFilter 鏈沒有結(jié)束的情況下,調(diào)用 WebFilter invokeFilter(this.currentFilter, this.chain, exchange) : //在 WebFilter 結(jié)束的情況下,調(diào)用 handler this.handler.handle(exchange));}
對于我們這里的 WebFilter 鏈的第一個 MetricsWebFilter
,假設(shè)啟用了對應(yīng)的采集統(tǒng)計的話,這時候生成的 Mono 就是:
return Mono.defer(() -> chain.filter(exchange).transformDeferred((call) -> { long start = System.nanoTime(); return call //成功時,記錄響應(yīng)時間 .doOnSuccess((done) -> MetricsWebFilter.this.onSuccess(exchange, start)) //失敗時,記錄響應(yīng)時間和異常 .doOnError((cause) -> MetricsWebFilter.this.onError(exchange, start, cause)); }););
這里為了方便,我們對代碼做了簡化,由于我們要將整個鏈路的所有 Mono 和 Flux 拼接在一起行程完整鏈路,所以原本是 MetricsWebFilter
中的 onSuccess(exchange, start)
方法,被改成了 MetricsWebFilter.this.onSuccess(exchange, start)
這種偽代碼。
接著,根據(jù)DefaultWebFilterChain
的源碼分析,chain.filter(exchange)
會繼續(xù) WebFilter 鏈路,到達下一個 WebFilter,即 TraceWebFilter
。經(jīng)過 TraceWebFilter
,Mono 就會變成:
return Mono.defer(() -> new MonoWebFilterTrace(source, chain.filter(exchange), TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
可以看出,在 TraceWebFilter
中,整個內(nèi)部 Mono (chain.filter(exchange)
后續(xù)的結(jié)果)都被封裝成了一個 MonoWebFilterTrace
,這也是保持鏈路追蹤信息的關(guān)鍵實現(xiàn)。
繼續(xù) WebFilter 鏈路,經(jīng)過最后一個 WebFilter WeightCalculatorWebFilter
; 這個 WebFilter 我們不關(guān)心,里面對路由權(quán)重做了一些計算操作,我們這里直接忽略即可。這樣我們就走完了所有 WebFilter 鏈路,來到了最后的調(diào)用 DefaultWebFilterChain.this.handler
,這個 handler 就是 org.springframework.web.reactive.DispatcherHandler
。在 DispatcherHandler 中,我們會計算出路由并發(fā)送請求到符合條件的 GatewayFilter。經(jīng)過 DispatcherHandler,Mono 會變成:
return Mono.defer(() -> new MonoWebFilterTrace(source, Flux.fromIterable(DispatcherHandler.this.handlerMappings) //讀取所有的 handlerMappings .concatMap(mapping -> mapping.getHandler(exchange)) //按順序調(diào)用所有的 handlerMappings 的 getHandler 方法,如果有對應(yīng)的 Handler 會返回,否則返回 Mono.empty(); .next() //找到第一個返回不是 Mono.empty() 的 Handler .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //調(diào)用對應(yīng)的 Handler .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //處理結(jié)果 TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
handlerMappings 包括:
org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndPointHandlerMapping
:由于我們項目中添加了 Actuator 相關(guān)依賴,所以這里有這個 HandlerMapping。Actuator 相關(guān)路徑映射,不是我們這里關(guān)心的。但是可以看出,Actuator 相關(guān)路徑優(yōu)先于 Spring Cloud Gateway 配置路由org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping
:由于我們項目中添加了 Actuator 相關(guān)依賴,所以這里有這個 HandlerMapping。使用 @ControllerEndpoint 或者 @RestControllerEndpoint 注解標注的 Actuator 相關(guān)路徑映射,不是我們這里關(guān)心的。org.springframework.web.reactive.function.server.support.RouterFunctionMapping
:在 Spring-WebFlux 中,你可以定義很多不同的 RouterFunction 來控制路徑路由,但這也不是我們這里關(guān)心的。但是可以看出,自定義的 RouterFunction 會優(yōu)先于 Spring Cloud Gateway 配置路由org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping
:針對 @RequestMapping 注解的路徑的 HandlerMapping,不是我們這里關(guān)心的。但是可以看出,如果你在 Spring Cloud Gateway 中指定 RequestMapping 路徑,會優(yōu)先于 Spring Cloud Gateway 配置路由。org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
:這個是 Spring Cloud Gateway 的 HandlerMapping,會讀取 Spring Cloud Gateway 配置并生成路由。這個是我們這里要詳細分析的。其實這些 handlerMappings,我們這里肯定走的是 RoutePredicateHandlerMapping
的相關(guān)邏輯,所以我們的 Mono 又可以簡化成:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.getHandler(exchange) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //調(diào)用對應(yīng)的 Handler .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //處理結(jié)果 TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
我們來看 RoutePredicateHandlerMapping
,首先這些 handlerMapping 都是繼承了抽象類 org.springframework.web.reactive.handler.AbstractHandlerMapping
, 前面我們拼接的 Mono 里面的 getHandler 的實現(xiàn)其實就在這個抽象類中:
public Mono
可以看出,其實核心就是每個實現(xiàn)類的 getHandlerInternal(exchange)
方法,所以在我們拼接的 Mono 中,我們會忽略抽象類中的針對 handler 之后的 map 處理。
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.getHandlerInternal(exchange) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //調(diào)用對應(yīng)的 Handler .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //處理結(jié)果 TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
接下來經(jīng)過 RoutePredicateHandlerMapping
的 getHandlerInternal(exchange)
方法,我們的 Mono 變成了:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.lookupRoute(exchange) //根據(jù)請求尋找路由 .flatMap((Function>) r -> { exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //將路由放入 Attributes 中,后面我們還會用到 return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler }).switchIfEmpty( //如果為 Mono.empty(),也就是沒找到路由 Mono.empty() //返回 Mono.empty() .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,記錄日志 if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .flatMap(handler -> DispatcherHandler.this.invokeHandler(exchange, handler)) //調(diào)用對應(yīng)的 Handler .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //處理結(jié)果 TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
RoutePredicateHandlerMapping.this.lookupRoute(exchange)
根據(jù)請求尋找路由,這個我們就不詳細展開了,其實就是根據(jù)你的 Spring Cloud Gateway 配置,找到合適的路由。接下來我們來看調(diào)用對應(yīng)的 Handler,即 FilteringWebHandler。DispatcherHandler.this.invokeHandler(exchange, handler)
我們這里也不詳細展開,我們知道其實就是調(diào)用 Handler 的 handle 方法,即 FilteringWebHandler 的 handle 方法,所以 我們的 Mono 變成了:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.lookupRoute(exchange) //根據(jù)請求尋找路由 .flatMap((Function>) r -> { exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //將路由放入 Attributes 中,后面我們還會用到 return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler }).switchIfEmpty( //如果為 Mono.empty(),也就是沒找到路由 Mono.empty() .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,記錄日志 if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .then(FilteringWebHandler.this.handle(exchange).then(Mono.empty())) //調(diào)用對應(yīng)的 Handler .flatMap(result -> DispatcherHandler.this.handleResult(exchange, result)), //處理結(jié)果 TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
由于調(diào)用對應(yīng)的 Handler,最后返回的是 Mono.empty()
,所以后面的 flatMap 其實不會執(zhí)行了。所以我們可以將最后的處理結(jié)果這一步去掉。所以我們的 Mono 就變成了:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.lookupRoute(exchange) //根據(jù)請求尋找路由 .flatMap((Function>) r -> { exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //將路由放入 Attributes 中,后面我們還會用到 return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler }).switchIfEmpty( //如果為 Mono.empty(),也就是沒找到路由 Mono.empty() .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,記錄日志 if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .then(FilteringWebHandler.this.handle(exchange).then(Mono.empty()))), //調(diào)用對應(yīng)的 Handler TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
FilteringWebHandler.this.handle(exchange)
其實就是從 Attributes 中取出路由,從路由中取出對應(yīng)的 GatewayFilters,與全局 GatewayFilters 放到同一個 List 中,并按照這些 GatewayFilter 的順序排序(可以通過實現(xiàn) org.springframework.core.Ordered
接口來制定順序),然后生成 DefaultGatewayFilterChain
即 GatewayFilter 鏈路。對應(yīng)的源碼是:
public Mono handle(ServerWebExchange exchange) { //從 Attributes 中取出路由,從路由中取出對應(yīng)的 GatewayFilters Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR); List gatewayFilters = route.getFilters(); //與全局 GatewayFilters 放到同一個 List 中 List combined = new ArrayList<>(this.globalFilters); combined.addAll(gatewayFilters); //按照這些 GatewayFilter 的順序排序(可以通過實現(xiàn) `org.springframework.core.Ordered` 接口來制定順序) AnnotationAwareOrderComparator.sort(combined); if (logger.isDebugEnabled()) { logger.debug("Sorted gatewayFilterFactories: " + combined); } //生成調(diào)用鏈 return new DefaultGatewayFilterChain(combined).filter(exchange);}
這個 GatewayFilter 調(diào)用鏈和 WebFilter 調(diào)用鏈類似,參考 DefaultGatewayFilterChain
的源碼:
public Mono filter(ServerWebExchange exchange) { return Mono.defer(() -> { //如果鏈路沒有結(jié)束,則繼續(xù)鏈路 if (this.index < filters.size()) { GatewayFilter filter = filters.get(this.index); //這里將 index + 1,也就是調(diào)用鏈路中的下一個 GatewayFilter DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1); //每個 filter 中如果想要繼續(xù)鏈路,則會調(diào)用 chain.filter(exchange),這也是我們開發(fā) GatewayFilter 的時候的使用方式 return filter.filter(exchange, chain); } else { //到達末尾,鏈路結(jié)束 return Mono.empty(); // complete } });}
所以,經(jīng)過 DefaultGatewayFilterChain
后,我們的 Mono 就會變成:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.lookupRoute(exchange) //根據(jù)請求尋找路由 .flatMap((Function>) r -> { exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //將路由放入 Attributes 中,后面我們還會用到 return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler }).switchIfEmpty( //如果為 Mono.empty(),也就是沒找到路由 Mono.empty() .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,記錄日志 if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .then(new DefaultGatewayFilterChain(combined).filter(exchange).then(Mono.empty()))), //調(diào)用對應(yīng)的 Handler TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
再繼續(xù)展開 DefaultGatewayFilterChain
的鏈路調(diào)用,可以得到:
return Mono.defer(() -> new MonoWebFilterTrace(source, RoutePredicateHandlerMapping.this.lookupRoute(exchange) //根據(jù)請求尋找路由 .flatMap((Function>) r -> { exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //將路由放入 Attributes 中,后面我們還會用到 return Mono.just(RoutePredicateHandlerMapping.this.webHandler); //返回 RoutePredicateHandlerMapping 的 FilteringWebHandler }).switchIfEmpty( //如果為 Mono.empty(),也就是沒找到路由 Mono.empty() .then(Mono.fromRunnable(() -> { //返回 Mono.empty() 之后,記錄日志 if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))) .switchIfEmpty(DispatcherHandler.this.createNotFoundError()) //如果沒有返回不為 Mono.empty() 的 handlerMapping,則直接返回 404 .then( Mono.defer(() -> { //如果鏈路沒有結(jié)束,則繼續(xù)鏈路 if (DefaultGatewayFilterChain.this.index < DefaultGatewayFilterChain.this.filters.size()) { GatewayFilter filter = DefaultGatewayFilterChain.this.filters.get(DefaultGatewayFilterChain.this.index); //這里將 index + 1,也就是調(diào)用鏈路中的下一個 GatewayFilter DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(DefaultGatewayFilterChain.this, DefaultGatewayFilterChain.this.index + 1); //每個 filter 中如果想要繼續(xù)鏈路,則會調(diào)用 chain.filter(exchange),這也是我們開發(fā) GatewayFilter 的時候的使用方式 return filter.filter(exchange, chain); } else { return Mono.empty(); //鏈路完成 } }) .then(Mono.empty())) ), //調(diào)用對應(yīng)的 Handler TraceWebFilter.this.isTracePresent(), TraceWebFilter.this, TraceWebFilter.this.spanFromContextRetriever()).transformDeferred((call) -> { //MetricsWebFilter 相關(guān)的處理,在前面的代碼中給出了,這里省略 }););
這樣,就形成了 Spring Cloud Gateway 針對路由請求的完整 Mono 調(diào)用鏈。
微信搜索“我的編程喵”關(guān)注公眾號,每日一刷,輕松提升技術(shù),斬獲各種offer:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/125381.html
摘要:在這里,會將上下文中載入的拼接成,然后調(diào)用其方法的,它是的處理請求業(yè)務(wù)的起點。添加相關(guān)依賴之后,會有這個。路由權(quán)重相關(guān)配置功能相關(guān)實現(xiàn)類,這個我們這里不關(guān)心。本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent我們繼續(xù)分析上一節(jié)提到的 WebHandler,經(jīng)過將請求封裝成 ServerWebExchange 的 HttpWebHand...
摘要:在這里,會將上下文中載入的拼接成,然后調(diào)用其方法的,它是的處理請求業(yè)務(wù)的起點。添加相關(guān)依賴之后,會有這個。路由權(quán)重相關(guān)配置功能相關(guān)實現(xiàn)類,這個我們這里不關(guān)心。 本系列代碼地址:??https://github.com/JoJoTec/spring-cloud-parent??我們繼續(xù)分析上一節(jié)提到的 ??WebHandle...
摘要:將請求封裝成將請求封裝成的接口定義是但是最外層傳進來的參數(shù)是和,需要將他們封裝成,這個工作就是在中做的。其實主要任務(wù)就是將各種參數(shù)封裝成除了和本次請求相關(guān)的和,還有會話管理器,編碼解碼器配置,國際化配置還有用于擴展。本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent接下來,將進入我們升級之路的又一大模塊,即網(wǎng)關(guān)模塊。網(wǎng)關(guān)模塊我們廢棄了...
摘要:升級之路版基本流程講解抽象類本系列代碼地址我們繼續(xù)分析上一節(jié)提到的。添加相關(guān)依賴之后,會有這個。路由權(quán)重相關(guān)配置功能相關(guān)實現(xiàn)類,這個我們這里不關(guān)心。這個是的,會讀取配置并生成路由。 本系列代碼地址:??https://github.com/JoJoTec/spring-cloud-parent??我們繼續(xù)分析上一節(jié)提到的 ...
摘要:對于異步的請求,使用的是異步客戶端即。要實現(xiàn)的配置設(shè)計以及使用舉例要實現(xiàn)的配置設(shè)計以及使用舉例首先,我們要實現(xiàn)的,其包含三個重試重試的要在負載均衡之前,因為重試的時候,我們會從負載均衡器獲取另一個實例進行重試,而不是在同一個實例上重試多次。 本系列代碼地址:https://github.com/JoJoTec/spring-cloud-parent 為何需要封裝異步 HT...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5181·2023-01-11 11:02
閱讀 4737·2023-01-11 11:02
閱讀 5534·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3990·2023-01-11 11:02