欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud網(wǎng)關(guān)組件Gateway原理深度解析

 更新時(shí)間:2023年07月07日 10:27:30   作者:白菜說技術(shù)  
Spring Cloud Gateway是Spring Cloud微服務(wù)生態(tài)下的網(wǎng)關(guān)組件,一些基礎(chǔ)的請(qǐng)求預(yù)處理的邏輯可以統(tǒng)一實(shí)現(xiàn)在網(wǎng)關(guān)這一層,這樣業(yè)務(wù)服務(wù)只需要專注于處理業(yè)務(wù)邏輯即可,所以本文就帶大家深度解析網(wǎng)關(guān)組件Gateway,需要的朋友可以參考下

引入網(wǎng)關(guān)的必要性

在微服務(wù)架構(gòu)下,我們一般會(huì)把相對(duì)獨(dú)立的業(yè)務(wù)或功能劃分為不同的服務(wù),不同服務(wù)之間相互隔離,獨(dú)立部署。這些微服務(wù)由服務(wù)注冊(cè)中心集中管理。對(duì)于來(lái)自外部的用戶請(qǐng)求來(lái)說,在處理請(qǐng)求的核心業(yè)務(wù)邏輯之前,一般還需要對(duì)請(qǐng)求做一些預(yù)處理,如權(quán)限校驗(yàn)、監(jiān)控統(tǒng)計(jì)、流量限制等。如果外部請(qǐng)求直接到達(dá)微服務(wù),那么所有的服務(wù)都需要各自負(fù)責(zé)處理這些功能,會(huì)造成這部分功能邏輯在各個(gè)服務(wù)重復(fù)出現(xiàn),增加了未來(lái)對(duì)這些基礎(chǔ)功能的維護(hù)升級(jí)的成本。

所以在微服務(wù)環(huán)境下,我們還需要一個(gè)網(wǎng)關(guān)組件來(lái)作為請(qǐng)求入口。一些基礎(chǔ)的請(qǐng)求預(yù)處理的邏輯可以統(tǒng)一實(shí)現(xiàn)在網(wǎng)關(guān)這一層,這樣業(yè)務(wù)服務(wù)只需要專注于處理業(yè)務(wù)邏輯即可。另外,引入網(wǎng)關(guān)作為統(tǒng)一請(qǐng)求入口之后,還可以利用網(wǎng)關(guān)來(lái)實(shí)現(xiàn)一些其他的功能,比如服務(wù)保護(hù)、灰度發(fā)布等。

1. Spring Cloud Gateway 簡(jiǎn)介

Spring Cloud Gateway 是 Spring Cloud 微服務(wù)生態(tài)下的網(wǎng)關(guān)組件。Spring Cloud Gateway 是基于 Spring 5 和 Spring Boot 2 搭建的,本質(zhì)上是一個(gè) Spring Boot 應(yīng)用。在詳細(xì)介紹其基本原理之前,先看一下通常而言,可以由微服務(wù)網(wǎng)關(guān)提供的功能。

在 Spring Cloud Gateway 發(fā)布之前,Spring Cloud 使用的是由 Netflix 開源的 Zuul 1 作為網(wǎng)關(guān)組件。Zuul 1 是基于傳統(tǒng)的 Servlet API 開發(fā)的,使用了阻塞的網(wǎng)絡(luò)模型,每個(gè)請(qǐng)求需要分配專門的線程處理,所以資源開銷比較大,在高并發(fā)的情況下需要?jiǎng)?chuàng)建大量的線程來(lái)處理請(qǐng)求,線程數(shù)目會(huì)成為系統(tǒng)的瓶頸。作為取代 Spring Cloud Zuul 的組件,Spring Cloud Gateway 網(wǎng)絡(luò)層使用了基于非阻塞的 Netty,解決了線程數(shù)瓶頸從而提升了系統(tǒng)性能。

微服務(wù)網(wǎng)關(guān)的功能

  • 請(qǐng)求路由:根據(jù)請(qǐng)求本身的屬性把請(qǐng)求轉(zhuǎn)發(fā)到不同的微服務(wù)是微服務(wù)網(wǎng)關(guān)的基本功能之一。業(yè)務(wù)運(yùn)維人員需要針對(duì)不同的服務(wù)配置路由,使網(wǎng)關(guān)能夠根據(jù)請(qǐng)求的 header、路徑、參數(shù)、協(xié)議等屬性將其轉(zhuǎn)發(fā)到對(duì)應(yīng)的服務(wù)。
  • 服務(wù)發(fā)現(xiàn):網(wǎng)關(guān)是微服務(wù)環(huán)境的請(qǐng)求入口。支持服務(wù)發(fā)現(xiàn)能使網(wǎng)關(guān)在轉(zhuǎn)發(fā)請(qǐng)求到目標(biāo)服務(wù)時(shí)充分利用服務(wù)注冊(cè)中心動(dòng)態(tài)管理服務(wù)實(shí)例的優(yōu)勢(shì),在配置路由轉(zhuǎn)發(fā)的目標(biāo)地址時(shí)也會(huì)更加方便。
  • 修改請(qǐng)求響應(yīng):網(wǎng)關(guān)在收到外部請(qǐng)求,將其轉(zhuǎn)發(fā)到目標(biāo)服務(wù)之前,可以根據(jù)需求對(duì)請(qǐng)求進(jìn)行修改,比如果更改請(qǐng)求 header、參數(shù)等。類似地,也可以在獲取到業(yè)務(wù)服務(wù)響應(yīng)之后,返回給用戶前對(duì)響應(yīng)進(jìn)行修改。
  • 權(quán)限校驗(yàn):某些業(yè)務(wù)場(chǎng)景在處理用戶請(qǐng)求時(shí)需要先對(duì)用戶進(jìn)行權(quán)限校驗(yàn),這部分邏輯也可以由網(wǎng)關(guān)來(lái)負(fù)責(zé)。請(qǐng)求在到達(dá)網(wǎng)關(guān)時(shí),由網(wǎng)關(guān)根據(jù)請(qǐng)求要訪問的業(yè)務(wù)接口先對(duì)用戶鑒權(quán),只有校驗(yàn)通過的請(qǐng)求才會(huì)轉(zhuǎn)發(fā)到對(duì)應(yīng)的服務(wù),而校驗(yàn)不通過的請(qǐng)求會(huì)被網(wǎng)關(guān)直接拒絕。這樣做能夠把拒絕無(wú)效請(qǐng)求這一步提前到網(wǎng)關(guān)這一層,減少無(wú)效的流量進(jìn)入到業(yè)務(wù)服務(wù)。
  • 限流熔斷:網(wǎng)關(guān)可以通過添加限流、熔斷等機(jī)制來(lái)對(duì)業(yè)務(wù)服務(wù)起保護(hù)作用,提升系統(tǒng)整體的可用性。根據(jù)業(yè)務(wù)服務(wù)的吞吐量,網(wǎng)關(guān)可以限制轉(zhuǎn)發(fā)到該服務(wù)的請(qǐng)求數(shù)量,超出限制的請(qǐng)求直接拒絕或降級(jí),這樣可以避免因?yàn)檫^多的請(qǐng)求導(dǎo)致業(yè)務(wù)服務(wù)負(fù)載過高的情況。當(dāng)業(yè)務(wù)服務(wù)異常時(shí),還可以通過熔斷的方式到達(dá)快速失敗的效果。
  • 請(qǐng)求重試:對(duì)于一些冪等的請(qǐng)求,當(dāng)網(wǎng)關(guān)轉(zhuǎn)發(fā)目標(biāo)服務(wù)失敗時(shí),可以在網(wǎng)關(guān)層做自動(dòng)重試。對(duì)于一些多實(shí)例部署服務(wù),重試時(shí)還可以考慮把請(qǐng)求轉(zhuǎn)發(fā)到不同的實(shí)例,以提高請(qǐng)求成功的概率。
  • 響應(yīng)緩存:當(dāng)用戶請(qǐng)求獲取的是一些靜態(tài)的或更新不頻繁的數(shù)據(jù)時(shí),一段時(shí)間內(nèi)多次請(qǐng)求獲取到的數(shù)據(jù)很可能是一樣的。對(duì)于這種情況可以將響應(yīng)緩存起來(lái)。這樣用戶請(qǐng)求可以直接在網(wǎng)關(guān)層得到響應(yīng)數(shù)據(jù),無(wú)需再去訪問業(yè)務(wù)服務(wù),減輕業(yè)務(wù)服務(wù)的負(fù)擔(dān)。
  • 響應(yīng)聚合:某些情況下用戶請(qǐng)求要獲取的響應(yīng)內(nèi)容可能會(huì)來(lái)自于多個(gè)業(yè)務(wù)服務(wù)。網(wǎng)關(guān)作為業(yè)務(wù)服務(wù)的調(diào)用方,可以把多個(gè)服務(wù)的響應(yīng)整合起來(lái),再一并返回給用戶。
  • 監(jiān)控統(tǒng)計(jì):因?yàn)榫W(wǎng)關(guān)是請(qǐng)求入口,所以在網(wǎng)關(guān)這一層可以方便地對(duì)外部的訪問請(qǐng)求做監(jiān)控和統(tǒng)計(jì),同時(shí)還可以對(duì)業(yè)務(wù)服務(wù)的響應(yīng)做監(jiān)控,方便發(fā)現(xiàn)異常情況。
  • 灰度流量:網(wǎng)關(guān)可以用來(lái)做服務(wù)流量的灰度切換。比如某個(gè)業(yè)務(wù)服務(wù)上線了新版本,那可以在網(wǎng)關(guān)這一層按照灰度策略,把一部分請(qǐng)求流量切換到新版本服務(wù)上,以達(dá)到驗(yàn)證新版本業(yè)務(wù)服務(wù)的功能和性能的效果。
  • 異常響應(yīng)處理:對(duì)于業(yè)務(wù)服務(wù)返回的異常響應(yīng),可以在網(wǎng)關(guān)層在返回給用戶之前做轉(zhuǎn)換處理。這樣可以把一些業(yè)務(wù)側(cè)返回的異常細(xì)節(jié)隱藏,轉(zhuǎn)換成用戶友好的錯(cuò)誤提示返回。

2. Spring Cloud Gateway 基本原理

Spring Cloud Gateway 使用了 Spring WebFlux 非阻塞網(wǎng)絡(luò)框架,網(wǎng)絡(luò)層默認(rèn)使用了高性能非阻塞的 Netty Server,解決了 Spring Cloud Zuul 因?yàn)樽枞木€程模型帶來(lái)的性能下降的問題。

Gateway 本身是一個(gè) Spring Boot 應(yīng)用,它處理請(qǐng)求是邏輯是根據(jù)配置的路由對(duì)請(qǐng)求進(jìn)行預(yù)處理和轉(zhuǎn)發(fā)。Gateway 有幾個(gè)比較核心的概念:

  • Route:一個(gè) Route 由路由 ID,轉(zhuǎn)發(fā) URI,多個(gè) Predicates 以及多個(gè) Filters 構(gòu)成。Gateway 上可以配置多個(gè) Routes。處理請(qǐng)求時(shí)會(huì)按優(yōu)先級(jí)排序,找到第一個(gè)滿足所有 Predicates 的 Route;
  • Predicate:表示路由的匹配條件,可以用來(lái)匹配請(qǐng)求的各種屬性,如請(qǐng)求路徑、方法、header 等。一個(gè) Route 可以包含多個(gè)子 Predicates,多個(gè)子 Predicates 最終會(huì)合并成一個(gè);
  • Filter:過濾器包括了處理請(qǐng)求和響應(yīng)的邏輯,可以分為 pre 和 post 兩個(gè)階段。多個(gè) Filter 在 pre 階段會(huì)按優(yōu)先級(jí)高到低順序執(zhí)行,post 階段則是反向執(zhí)行。Gateway 包括兩類 Filter。

全局 Filter:每種全局 Filter 全局只會(huì)有一個(gè)實(shí)例,會(huì)對(duì)所有的 Route 都生效。

路由 Filter:路由 Filter 是針對(duì) Route 進(jìn)行配置的,不同的 Route 可以使用不同的參數(shù),因此會(huì)創(chuàng)建不同的實(shí)例。

Gateway 在啟動(dòng)時(shí)會(huì)創(chuàng)建 Netty Server,由它接收來(lái)自 Client 的請(qǐng)求。收到請(qǐng)求后根據(jù)路由的匹配條件找到第一個(gè)滿足條件的路由,然后請(qǐng)求在被該路由配置的過濾器處理后由 Netty Client 轉(zhuǎn)到目標(biāo)服務(wù)。服務(wù)返回響應(yīng)后會(huì)再次被過濾器處理,最后返回給 Client。

Gateway 路由配置

Spring Cloud Gateway 本身提供了很多 Predicate 和 Filter 的實(shí)現(xiàn),一些基本的功能可以通過這些現(xiàn)成的 Predicate 和 Filter 配置實(shí)現(xiàn)。這些 Gateway 本身提供的 Predicate 和 Filter 在官方文檔上有詳細(xì)的介紹,這里給一個(gè)大致的例子:

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: lb://service-A
        predicates:
         - Path=/hello
        filters:
        - SetRequestHeader=X-Request-Red, Blue

路由是 Gateway 的核心構(gòu)件,不同的路由根據(jù)匹配條件可以處理不同類型的請(qǐng)求,并轉(zhuǎn)發(fā)到對(duì)應(yīng)的目標(biāo)服務(wù)。一個(gè)路由由以下幾個(gè)屬性組成:

  • Id: 路由 ID;
  • Uri: 轉(zhuǎn)發(fā)請(qǐng)求的目標(biāo)地址;
  • Order: 順序(優(yōu)先級(jí));
  • Predicate: 匹配條件。多個(gè) Predicates 會(huì)合并成一個(gè)聚合的條件;
  • Filters: 路由過濾器。這些過濾器最終會(huì)和全局過濾器一起排序處理匹配成功的請(qǐng)求;
  • Metadata: 額外的元數(shù)據(jù)。

Gateway 請(qǐng)求路由原理

Gateway 使用了 Spring WebFlux 框架,該框架處理請(qǐng)求的入口在類  DispatcherHandler  。它會(huì)根據(jù)提供的  HandlerMapping  來(lái)獲取處理請(qǐng)求的  Handler  方法。Gateway 應(yīng)用對(duì)  HandlerMapping  的實(shí)現(xiàn)是  RoutePredicateHandlerMapping 。

進(jìn)來(lái)的請(qǐng)求由  DispatcherHandler  處理。

DispatcherHandler  根據(jù)  RoutePredicateHandlerMapping  獲取  Handler  方法。

RoutePredicateHandlerMapping  依賴  RouteLocator  獲取所有路由配置并根據(jù)匹配條件打到請(qǐng)求匹配的路由。

RoutePredicateHandlerMapping  把請(qǐng)求交給  FilteringWebHandler  處理。

FilteringWebHandler  從請(qǐng)求匹配的路由獲取對(duì)應(yīng)的路由 Filter,并和全局 Filter 合并構(gòu)造  GatewayFilterChain ,請(qǐng)求最終由  GatewayFilterChain  里的 Filter 按順序處理。

Spring Cloud Gateway 上下文(ServerWebExchange)

SpringCloud Gateway 的上下文是 ServerWebExchange,請(qǐng)求的信息都存儲(chǔ)在 ServerWebExchange 中,在網(wǎng)關(guān)上的后續(xù)操作都是基于上下文操作的,在 http 請(qǐng)求到達(dá)網(wǎng)關(guān)之后,網(wǎng)關(guān)入口是ReactorHttpHandlerAdapter#apply 方法,去獲取請(qǐng)求的 request 和 response,構(gòu)建當(dāng)次請(qǐng)求的上下文供后續(xù) filter 使用:

public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {
        @Override
	public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
		NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
		try {
		        // 獲取請(qǐng)求的Request,構(gòu)建ReactorServerHttpRequest
			ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
			// 構(gòu)建ServerHttpResponse
			ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
			if (request.getMethod() == HttpMethod.HEAD) {
				response = new HttpHeadResponseDecorator(response);
			}
			// 交給HttpWebHandlerAdapter構(gòu)建上下文ServerWebExchange
			return this.httpHandler.handle(request, response)
					.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
					.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
		}
		catch (URISyntaxException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to get request URI: " + ex.getMessage());
			}
			reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
			return Mono.empty();
		}
	}
}

構(gòu)建完 request 和 response 后,交給 HttpWebHandlerAdapter 構(gòu)建上下文 ServerWebExchange:

public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
	public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
		if (this.forwardedHeaderTransformer != null) {
			request = this.forwardedHeaderTransformer.apply(request);
		}
		// 構(gòu)建請(qǐng)求的上下文
		ServerWebExchange exchange = createExchange(request, response);
		LogFormatUtils.traceDebug(logger, traceOn ->
				exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
						(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
		return getDelegate().handle(exchange)
				.doOnSuccess(aVoid -> logResponse(exchange))
				.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
				.then(Mono.defer(response::setComplete));
	}
}

Spring Cloud Gateway 讀取路由(RouteDefinition)

我們?cè)谂渲梦募信渲玫囊粋€(gè)路由規(guī)則,對(duì)應(yīng)到 Java 類就是 GatewayProperties,Spring Boot 會(huì)將配置文件映射為 Java 類,例如上文的配置:

spring:
  cloud:
    gateway:
      routes:
      - id: test_route
        uri: lb://service-A
        predicates:
         - Path=/hello
        filters:
        - SetRequestHeader=X-Request-Red, Blue

路由信息映射到 GatewayProperties 后如何獲取其中的 RouteDefinition?

答案是通過 RouteDefinitionLocator。

public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
	private final GatewayProperties properties;
	// 構(gòu)造函數(shù)設(shè)置properties
	public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
		this.properties = properties;
	}
	// 從properties中讀取RouteDefinition
	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return Flux.fromIterable(this.properties.getRoutes());
	}
}

當(dāng)然我們獲取路由信息的地方不止 properties 一種,還可以從 內(nèi)存,緩存,甚至注冊(cè)中心等。CompositeRouteDefinitionLocator 利用委派器模式允許我們組合讀取路由信息。

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
	private final Flux<RouteDefinitionLocator> delegates;
	// 將 RouteDefinitionLocator 組合
	public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
		this.delegates = delegates;
	}
	// 委托給 RouteDefinitionRepository 執(zhí)行讀取
	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {
		return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
	}
}

Spring Cloud Gateway 的 GlobalFilter

GlobalFilter 是所有被 Gateway 攔截的 http 請(qǐng)求都要做的處理;GatewayFilter 是根據(jù)路由配置匹配predicate 的 http 請(qǐng)求才會(huì)做的處理。

全局?jǐn)r截器,是所有被攔截到的 http 請(qǐng)求都要去做的處理;例如拿到一個(gè) http 請(qǐng)求后,我們的目的是轉(zhuǎn)發(fā)到下游服務(wù),請(qǐng)求結(jié)果并返回,那么所有被攔截到的 http 請(qǐng)求都需要做下列幾件事:

  • 按照 predicate 把符合規(guī)則的 url 轉(zhuǎn)換為真正要去請(qǐng)求的 url;
  • 調(diào)用真正的下游服務(wù)(基于 netty 實(shí)現(xiàn)的 http 調(diào)用,具體代碼在 NettyRoutingFilter 類中);
  • 得到 response,返回給調(diào)用方。

public interface GlobalFilter {
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

接口中只有一個(gè) filter 方法,實(shí)現(xiàn)類實(shí)現(xiàn)該接口后在 filter 中去做具體攔截邏輯,這些 Filter 都實(shí)現(xiàn)了 GlobalFilter 接口:

  • AdaptCachedBodyGlobalFilter:優(yōu)先級(jí)最高的 Filter,請(qǐng)求到 gateway 后,將上下文ServerWebExchange 中已有的緩存刪除 請(qǐng)求信息,將此次的請(qǐng)求信息緩存到上下文中。

  • ForwardPathFilter:如果該請(qǐng)求還未被路由或 URI對(duì)象的屬性不是 forward,則將該請(qǐng)求對(duì)應(yīng)配置的 Route 信息中 uri 的 path 設(shè)置到上下文 ServerWebExchange 中。

  • RouteToRequestUrlFilter:將此次請(qǐng)求的 uri 和配置的 Route 規(guī)則做 merged 處理,拿到真正代理的下游服務(wù)的地址,將得到的 url 放到上下文中,key 為 GATEWAY_REQUEST_URL_ATTR。

  • LoadBalancerClientFilter:網(wǎng)關(guān)提供了負(fù)載均衡的 Filter,具體負(fù)載規(guī)則可以自己實(shí)現(xiàn)。

  • NoLoadBalancerClientFilter:沒有負(fù)載均衡的攔截器。

  • NettyRoutingFilter:網(wǎng)關(guān)的 http 是基于 netty 實(shí)現(xiàn)的,若此次請(qǐng)求 scheme 是 http 或 https 則使用基于 netty 的 httpClient 執(zhí)行調(diào)用,將返回結(jié)果寫入上下文中。

  • NettyWriteResponseFilter:基于 Web Flux,若上下文中存在 CLIENT_RESPONSE_CONN_ATTR,將響應(yīng)數(shù)據(jù)返回。

  • WebClientHttpRoutingFilter:作用同 NettyRoutingFilter,方式同 LoadBalancerClientFilter。

  • WebsocketRoutingFilter:路由 WebSocket 請(qǐng)求,校驗(yàn)邏輯在WebsocketRoutingFilter#changeSchemeIfIsWebSocketUpgrade 中。

  • WebClientWriteResponseFilter:作用同 NettyWriteResponseFilter。

  • ForwardRoutingFilter:設(shè)置此次請(qǐng)求已被路由。

  • GatewayMetricsFilter:統(tǒng)計(jì)網(wǎng)關(guān)的性能指標(biāo)。

Spring Cloud Gateway 的 GatewayFilter

GatewayFilter 是面向開發(fā)人員的,因需適配,當(dāng)我們需要給符合 predicate 的 url 做一些處理時(shí)通過配置就可添加,例如,我們想給 path 匹配上 /test/** 的 url 添加 header,通過下列配置就可添加,這類配置是根據(jù)業(yè)務(wù)需求進(jìn)行的特殊配置。

public interface GatewayFilter extends ShortcutConfigurable {
	/**
	 * Name key.
	 */
	String NAME_KEY = "name";
	/**
	 * Value key.
	 */
	String VALUE_KEY = "value";
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

接口定義中多了 NAME_KEY 和 VALUE_KEY,原因是 GatewayFilter 是面向開發(fā)人員的,例如我們需要配置給 path符合 /test/** 的請(qǐng)求添加 header 時(shí),header 是 key-value 形式,這時(shí)候就用到了:

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
	@Override
	public GatewayFilter apply(NameValueConfig config) {
		return (exchange, chain) -> {
		// 將要添加的key-value添加到上下文的header中
                    ServerHttpRequest request = exchange.getRequest().mutate()
                                    .header(config.getName(), config.getValue()).build();
                    return chain.filter(exchange.mutate().request(request).build());
		};
	}
}

GlobalFilter 和 GatewayFilter 整合應(yīng)用

每個(gè) Filter 中都有一個(gè) Order 屬性,在執(zhí)行時(shí)是在 FilteringWebHandler#handle方法 中對(duì) GlobalFilter 和 GatewayFilter 進(jìn)行的整合和排序,具體執(zhí)行在 FilteringWebHandler#filter方法

    /**
    * 整合Filter 
    */
    public Mono<Void> handle(ServerWebExchange exchange) {
            // 根據(jù)Route信息取出配置的GatewayFilter集合
            Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
            List<GatewayFilter> gatewayFilters = route.getFilters();
            // 取出globalFilters
            List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
            // 將GatewayFilter添加到combined
            combined.addAll(gatewayFilters);
            // combined根據(jù)Order排優(yōu)先級(jí)
            AnnotationAwareOrderComparator.sort(combined);
            if (logger.isDebugEnabled()) {
                    logger.debug("Sorted gatewayFilterFactories: " + combined);
            }
            return new DefaultGatewayFilterChain(combined).filter(exchange);
    }
    /**
    * 執(zhí)行Filter 
    */
    public Mono<Void> filter(ServerWebExchange exchange) {
            return Mono.defer(() -> {
                    if (this.index < filters.size()) {
                            GatewayFilter filter = filters.get(this.index);
                            DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
                                            this.index + 1);
                            return filter.filter(exchange, chain);
                    }
                    else {
                            return Mono.empty(); // complete
                    }
            });
    }

GlobalFilter 和 GatewayFilter 自定義 Filter

  • 自定義 GlobalFilter:GlobalFilter 具體的實(shí)現(xiàn)方式是實(shí)現(xiàn)接口,每個(gè) filter 都實(shí)現(xiàn)了 GlobalFilter 接口:
public class GlobalTestFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if("符合業(yè)務(wù)邏輯,處理完業(yè)務(wù)邏輯,繼續(xù)執(zhí)行下一個(gè)filter"){
            return chain.filter(exchange);
        }
        //不符合業(yè)務(wù)邏輯,直接返回
        return "按照不符合業(yè)務(wù)邏輯處理";
    }
}
  • 自定義 GatewayFilter:GatewayFilter 具體的實(shí)現(xiàn)方式是工廠,每個(gè)工廠都繼承了 AbstractGatewayFilterFactory:
public class TestGatewayFilterFactory extends AbstractGatewayFilterFactory<TestGatewayFilterFactory.Config> {
    public TestGatewayFilterFactory() {
        super(TestGatewayFilterFactory.Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if("符合條件,處理業(yè)務(wù)邏輯,繼續(xù)執(zhí)行下一個(gè)Filter"){
                return chain.filter(exchange);
            }
             // 不符合條件,直接返回
            return "false";
        };
    }
    public static class Config {
        private String businessAttributes;
        public String getBusinessAttributes() {
            return businessAttributes;
        }
        public void setBusinessAttributes(String businessAttributes) {
            this.businessAttributes = businessAttributes;
        }
    }
}

3. Spring Cloud Gateway 工作過程

網(wǎng)關(guān)啟動(dòng)階段

  • Yaml 文件和 GatewayProperties 文件映射,映射處理源碼在 JavaBeanBinder.BeanProperty#getValue –> CollectionBinder#merge —> Binder#bindBean;
  • 加載 Locator Bean,為后續(xù)讀取 RouteDefinition 做準(zhǔn)備【GatewayAutoConfiguration】;
public class GatewayAutoConfiguration {
	@Bean
	@ConditionalOnMissingBean
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
			GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}
	@Bean
	@ConditionalOnMissingBean(RouteDefinitionRepository.class)
	public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
		return new InMemoryRouteDefinitionRepository();
	}
	@Bean
	@Primary
	public RouteDefinitionLocator routeDefinitionLocator(
			List<RouteDefinitionLocator> routeDefinitionLocators) {
		return new CompositeRouteDefinitionLocator(
				Flux.fromIterable(routeDefinitionLocators));
	}
	@Bean
	@Primary
	public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
		return new CachingRouteLocator(
				new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
	}
}
  • 初始化GlobalFilters【FilteringWebHandler】;
public class GatewayAutoConfiguration {
	@Bean
	public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
		return new FilteringWebHandler(globalFilters);
	}
}
public class FilteringWebHandler implements WebHandler {
	private final List<GatewayFilter> globalFilters;
	// 構(gòu)造函數(shù)中設(shè)置globalFiltersglobalFilters
	public FilteringWebHandler(List<GlobalFilter> globalFilters) {
		this.globalFilters = loadFilters(globalFilters);
	}
	// 設(shè)置globalFilters
	private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
		return filters.stream().map(filter -> {
			GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
			if (filter instanceof Ordered) {
				int order = ((Ordered) filter).getOrder();
				return new OrderedGatewayFilter(gatewayFilter, order);
			}
			return gatewayFilter;
		}).collect(Collectors.toList());
	}
}
  • 初始化 predicates,gatewayFilters,getRoutes【GatewayAutoConfiguration –> RouteDefinitionRouteLocator】;
public class RouteDefinitionRouteLocator
		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
	// 構(gòu)造函數(shù)中初始化
	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
			List<RoutePredicateFactory> predicates,
			List<GatewayFilterFactory> gatewayFilterFactories,
			GatewayProperties gatewayProperties, ConversionService conversionService) {
		this.routeDefinitionLocator = routeDefinitionLocator;
		this.conversionService = conversionService;
		initFactories(predicates);
		gatewayFilterFactories.forEach(
				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
		this.gatewayProperties = gatewayProperties;
	}
	// 設(shè)置predicate工廠
	private void initFactories(List<RoutePredicateFactory> predicates) {
		predicates.forEach(factory -> {
			String key = factory.name();
			if (this.predicates.containsKey(key)) {
				this.logger.warn("A RoutePredicateFactory named " + key
						+ " already exists, class: " + this.predicates.get(key)
						+ ". It will be overwritten.");
			}
			this.predicates.put(key, factory);
			if (logger.isInfoEnabled()) {
				logger.info("Loaded RoutePredicateFactory [" + key + "]");
			}
		});
	}
	public Flux<Route> getRoutes() {
		// 從RouteDefinitions轉(zhuǎn)換為Route,轉(zhuǎn)換過程在convertToRoute方法中實(shí)現(xiàn)
		return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute)
				.map(route -> {
					if (logger.isDebugEnabled()) {
						logger.debug("RouteDefinition matched: " + route.getId());
					}
					return route;
				});
	}
	// RouteDefinition到Route的轉(zhuǎn)換
	private Route convertToRoute(RouteDefinition routeDefinition) {
		// 從routeDefinition獲取predicate
		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
		// 從routeDefinition獲取gatewayFilters
		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
		// 構(gòu)造Route
		return Route.async(routeDefinition).asyncPredicate(predicate)
				.replaceFilters(gatewayFilters).build();
	}
	// 獲取GatewayFilters
	private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
		List<GatewayFilter> filters = new ArrayList<>();
		// 如果默認(rèn)filter不為空,則去加載
		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
					this.gatewayProperties.getDefaultFilters()));
		}
		// 如果Filter不為空,則
		if (!routeDefinition.getFilters().isEmpty()) {
			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
					routeDefinition.getFilters()));
		}
		AnnotationAwareOrderComparator.sort(filters);
		return filters;
	}
	@SuppressWarnings("unchecked")
	private List<GatewayFilter> loadGatewayFilters(String id,
			List<FilterDefinition> filterDefinitions) {
		List<GatewayFilter> filters = filterDefinitions.stream().map(definition -> {
			// 從gatewayFilterFactories中根據(jù)key獲取factory
			GatewayFilterFactory factory = this.gatewayFilterFactories
					.get(definition.getName());
			if (factory == null) {
				throw new IllegalArgumentException(
						"Unable to find GatewayFilterFactory with name "
								+ definition.getName());
			}
			// 獲取definition設(shè)置的Filter值
			Map<String, String> args = definition.getArgs();
			if (logger.isDebugEnabled()) {
				logger.debug("RouteDefinition " + id + " applying filter " + args + " to "
						+ definition.getName());
			}
			Map<String, Object> properties = factory.shortcutType().normalize(args,
					factory, this.parser, this.beanFactory);
			// 每一個(gè)工廠中都有一個(gè)靜態(tài)內(nèi)部類Config,目的是存儲(chǔ)我們?cè)O(shè)置的Filter值
			Object configuration = factory.newConfig();
			// 將后幾個(gè)參數(shù)的信息綁定到configuration
			ConfigurationUtils.bind(configuration, properties,
					factory.shortcutFieldPrefix(), definition.getName(), validator,
					conversionService);
			// 獲得GatewayFilter
			GatewayFilter gatewayFilter = factory.apply(configuration);
			if (this.publisher != null) {
				this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
			}
			return gatewayFilter;
		}).collect(Collectors.toList());
		ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
		for (int i = 0; i < filters.size(); i++) {
			GatewayFilter gatewayFilter = filters.get(i);
			if (gatewayFilter instanceof Ordered) {
				ordered.add(gatewayFilter);
			}
			else {
				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
			}
		}
		return ordered;
	}
}

請(qǐng)求處理階段

  • ReactorHttpHandlerAdapter#apply 方法是請(qǐng)求到網(wǎng)關(guān)執(zhí)行的入口;
public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {
        public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
		NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
		try {
			// 獲取請(qǐng)求的request和response
			ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
			ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
			if (request.getMethod() == HttpMethod.HEAD) {
				response = new HttpHeadResponseDecorator(response);
			}
			// 給到HttpWebHandlerAdapter執(zhí)行構(gòu)建
			return this.httpHandler.handle(request, response)
					.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
					.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
		}
		catch (URISyntaxException ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to get request URI: " + ex.getMessage());
			}
			reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
			return Mono.empty();
		}
	}
}
  • HttpWebHandlerAdapter#handle 構(gòu)建網(wǎng)關(guān)上下文 ServerWebExchange;
public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHandler {
	public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
		if (this.forwardedHeaderTransformer != null) {
			request = this.forwardedHeaderTransformer.apply(request);
		}
		// 根據(jù)請(qǐng)求的request、response構(gòu)建網(wǎng)關(guān)上下文
		ServerWebExchange exchange = createExchange(request, response);
		LogFormatUtils.traceDebug(logger, traceOn ->
				exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
						(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
		return getDelegate().handle(exchange)
				.doOnSuccess(aVoid -> logResponse(exchange))
				.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
				.then(Mono.defer(response::setComplete));
	}
}
  • DispatcherHandler 用于 Http 請(qǐng)求處理器/控制器的中央分發(fā)處理器,把請(qǐng)求分發(fā)給已經(jīng)注冊(cè)的處理程序處理,DispatcherHandler 遍歷 Mapping 獲取對(duì)應(yīng)的 handler,網(wǎng)關(guān)一共有 6 個(gè) handlerMapping【此處會(huì)找到 RoutePredicateHandlerMapping,通過 RoutePredicateHandlerMapping 獲取 FilteringWebHandler,通過 FilteringWebHandler 獲取】;
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		// 遍歷mapping獲取handler
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}
}
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
	private final FilteringWebHandler webHandler;
	private final RouteLocator routeLocator;
	private final Integer managementPort;
	private final ManagementPortType managementPortType;
	// 網(wǎng)關(guān)啟動(dòng)時(shí)進(jìn)行了初始化
	public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
			RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
			Environment environment) {
		this.webHandler = webHandler;
		this.routeLocator = routeLocator;
		this.managementPort = getPortProperty(environment, "management.server.");
		this.managementPortType = getManagementPortType(environment);
		setOrder(1);
		setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
	}
	protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
		// don't handle requests on management port if set and different than server port
		if (this.managementPortType == DIFFERENT && this.managementPort != null
				&& exchange.getRequest().getURI().getPort() == this.managementPort) {
			return Mono.empty();
		}
		exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
		return lookupRoute(exchange)
				// .log("route-predicate-handler-mapping", Level.FINER) //name this
				.flatMap((Function<Route, Mono<?>>) r -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					if (logger.isDebugEnabled()) {
						logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r);
					}
					exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
					// 返回FilteringWebHandler
					return Mono.just(webHandler);
				}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					if (logger.isTraceEnabled()) {
						logger.trace("No RouteDefinition found for ["
								+ getExchangeDesc(exchange) + "]");
					}
				})));
	}
}
  • RoutePredicateHandlerMapping#lookupRoute 匹配路由,根據(jù) routeLocator 獲取我們?cè)谂渲梦椅募信渲玫?Route,和當(dāng)前請(qǐng)求的路由做匹配;
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
	protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		// routeLocator獲取我們?cè)谂渲梦椅募信渲玫腞oute
		return this.routeLocator.getRoutes()
				.concatMap(route -> Mono.just(route).filterWhen(r -> {
					exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
					// 當(dāng)前請(qǐng)求的路由做匹配
					return r.getPredicate().apply(exchange);
				})
						.doOnError(e -> logger.error(
								"Error applying predicate for route: " + route.getId(),
								e))
						.onErrorResume(e -> Mono.empty()))
				.next()
				.map(route -> {
					if (logger.isDebugEnabled()) {
						logger.debug("Route matched: " + route.getId());
					}
					validateRoute(route, exchange);
					return route;
				});
	}
}
  • FilteringWebHandler 創(chuàng)建過濾器鏈,執(zhí)行過濾器;
public class FilteringWebHandler implements WebHandler {
	// 創(chuàng)建過濾器鏈
	public Mono<Void> handle(ServerWebExchange exchange) {
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		List<GatewayFilter> gatewayFilters = route.getFilters();
		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		AnnotationAwareOrderComparator.sort(combined);
		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}
	private static class DefaultGatewayFilterChain implements GatewayFilterChain {
		// 調(diào)用過濾器
		public Mono<Void> filter(ServerWebExchange exchange) {
			return Mono.defer(() -> {
				if (this.index < filters.size()) {
					GatewayFilter filter = filters.get(this.index);
					DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
							this.index + 1);
					// 執(zhí)行調(diào)用
					return filter.filter(exchange, chain);
				}
				else {
					return Mono.empty(); // complete
				}
			});
		}
	}
}

以上就是SpringCloud網(wǎng)關(guān)組件Gateway原理深度解析的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud Gateway原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中Springboot集成Kafka實(shí)現(xiàn)消息發(fā)送和接收功能

    Java中Springboot集成Kafka實(shí)現(xiàn)消息發(fā)送和接收功能

    Kafka是一個(gè)高吞吐量的分布式發(fā)布-訂閱消息系統(tǒng),主要用于處理大規(guī)模數(shù)據(jù)流,它由生產(chǎn)者、消費(fèi)者、主題、分區(qū)和代理等組件構(gòu)成,Kafka可以實(shí)現(xiàn)消息隊(duì)列、數(shù)據(jù)存儲(chǔ)和流處理等功能,在Java中,可以使用Spring Boot集成Kafka實(shí)現(xiàn)消息的發(fā)送和接收,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • 為什么說要慎用SpringBoot @ComponentScan

    為什么說要慎用SpringBoot @ComponentScan

    本文主要介紹了為什么說要慎用SpringBoot @ComponentScan,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • Java生成PDF文件的實(shí)例代碼

    Java生成PDF文件的實(shí)例代碼

    Java生成PDF文件的實(shí)例代碼,需要的朋友可以參考一下
    2013-05-05
  • Java并發(fā)系列之Semaphore源碼分析

    Java并發(fā)系列之Semaphore源碼分析

    這篇文章主要為大家詳細(xì)介紹了Java并發(fā)系列之Semaphore源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Elasticsearch學(xué)習(xí)之Terms?set?查詢

    Elasticsearch學(xué)習(xí)之Terms?set?查詢

    這篇文章主要為大家介紹了Elasticsearch學(xué)習(xí)Terms?set?查詢示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • java中MultipartFile互轉(zhuǎn)File的方法

    java中MultipartFile互轉(zhuǎn)File的方法

    本文主要介紹了java中MultipartFile互轉(zhuǎn)File的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java設(shè)計(jì)模式中的建造者(Builder)模式解讀

    Java設(shè)計(jì)模式中的建造者(Builder)模式解讀

    這篇文章主要介紹了Java設(shè)計(jì)模式中的建造者(Builder)模式解讀, 建造者模式是一種創(chuàng)建對(duì)象的設(shè)計(jì)模式,它通過將對(duì)象的構(gòu)建過程分解為多個(gè)步驟,并使用一個(gè)建造者類來(lái)封裝這些步驟,從而使得對(duì)象的構(gòu)建過程更加靈活和可擴(kuò)展,需要的朋友可以參考下
    2023-10-10
  • Spring底層核心源碼原理解析

    Spring底層核心源碼原理解析

    這篇文章主要介紹了Spring底層核心源碼原理解析,當(dāng)在某個(gè)方法上加了@Transactional注解后,就表示該方法在調(diào)用時(shí)會(huì)開啟Spring事務(wù),而這個(gè)方法所在的類所對(duì)應(yīng)的Bean對(duì)象會(huì)是該類的代理對(duì)象,需要的朋友可以參考下
    2023-09-09
  • SpringBoot讀取多環(huán)境配置文件的幾種方式

    SpringBoot讀取多環(huán)境配置文件的幾種方式

    這篇文章主要給大家介紹了SpringBoot讀取多環(huán)境配置文件的幾種方式,文章通過代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-10-10
  • Java數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)跳表

    Java數(shù)據(jù)結(jié)構(gòu)之實(shí)現(xiàn)跳表

    今天帶大家來(lái)學(xué)習(xí)Java數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識(shí),文中對(duì)用Java實(shí)現(xiàn)跳表作了非常詳細(xì)的圖文解說及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論