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

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

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

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

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

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

1. Spring Cloud Gateway 簡介

Spring Cloud Gateway 是 Spring Cloud 微服務生態(tài)下的網(wǎng)關(guān)組件。Spring Cloud Gateway 是基于 Spring 5 和 Spring Boot 2 搭建的,本質(zhì)上是一個 Spring Boot 應用。在詳細介紹其基本原理之前,先看一下通常而言,可以由微服務網(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ò)模型,每個請求需要分配專門的線程處理,所以資源開銷比較大,在高并發(fā)的情況下需要創(chuàng)建大量的線程來處理請求,線程數(shù)目會成為系統(tǒng)的瓶頸。作為取代 Spring Cloud Zuul 的組件,Spring Cloud Gateway 網(wǎng)絡(luò)層使用了基于非阻塞的 Netty,解決了線程數(shù)瓶頸從而提升了系統(tǒng)性能

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

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

2. Spring Cloud Gateway 基本原理

Spring Cloud Gateway 使用了 Spring WebFlux 非阻塞網(wǎng)絡(luò)框架,網(wǎng)絡(luò)層默認使用了高性能非阻塞的 Netty Server,解決了 Spring Cloud Zuul 因為阻塞的線程模型帶來的性能下降的問題。

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

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

全局 Filter:每種全局 Filter 全局只會有一個實例,會對所有的 Route 都生效。

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

Gateway 在啟動時會創(chuàng)建 Netty Server,由它接收來自 Client 的請求。收到請求后根據(jù)路由的匹配條件找到第一個滿足條件的路由,然后請求在被該路由配置的過濾器處理后由 Netty Client 轉(zhuǎn)到目標服務。服務返回響應后會再次被過濾器處理,最后返回給 Client。

Gateway 路由配置

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

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

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

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

Gateway 請求路由原理

Gateway 使用了 Spring WebFlux 框架,該框架處理請求的入口在類  DispatcherHandler  。它會根據(jù)提供的  HandlerMapping  來獲取處理請求的  Handler  方法。Gateway 應用對  HandlerMapping  的實現(xiàn)是  RoutePredicateHandlerMapping

進來的請求由  DispatcherHandler  處理。

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

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

RoutePredicateHandlerMapping  把請求交給  FilteringWebHandler  處理。

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

Spring Cloud Gateway 上下文(ServerWebExchange)

SpringCloud Gateway 的上下文是 ServerWebExchange,請求的信息都存儲在 ServerWebExchange 中,在網(wǎng)關(guān)上的后續(xù)操作都是基于上下文操作的,在 http 請求到達網(wǎng)關(guān)之后,網(wǎng)關(guān)入口是ReactorHttpHandlerAdapter#apply 方法,去獲取請求的 request 和 response,構(gòu)建當次請求的上下文供后續(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 {
		        // 獲取請求的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)建請求的上下文
		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)

我們在配置文件中配置的一個路由規(guī)則,對應到 Java 類就是 GatewayProperties,Spring Boot 會將配置文件映射為 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());
	}
}

當然我們獲取路由信息的地方不止 properties 一種,還可以從 內(nèi)存,緩存,甚至注冊中心等。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 請求都要做的處理;GatewayFilter 是根據(jù)路由配置匹配predicate 的 http 請求才會做的處理。

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

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

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

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

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

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

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

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

  • NoLoadBalancerClientFilter:沒有負載均衡的攔截器。

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

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

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

  • WebsocketRoutingFilter:路由 WebSocket 請求,校驗邏輯在WebsocketRoutingFilter#changeSchemeIfIsWebSocketUpgrade 中。

  • WebClientWriteResponseFilter:作用同 NettyWriteResponseFilter。

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

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

Spring Cloud Gateway 的 GatewayFilter

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

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/** 的請求添加 header 時,header 是 key-value 形式,這時候就用到了:

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 整合應用

每個 Filter 中都有一個 Order 屬性,在執(zhí)行時是在 FilteringWebHandler#handle方法 中對 GlobalFilter 和 GatewayFilter 進行的整合和排序,具體執(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)先級
            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 具體的實現(xiàn)方式是實現(xiàn)接口,每個 filter 都實現(xiàn)了 GlobalFilter 接口:
public class GlobalTestFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if("符合業(yè)務邏輯,處理完業(yè)務邏輯,繼續(xù)執(zhí)行下一個filter"){
            return chain.filter(exchange);
        }
        //不符合業(yè)務邏輯,直接返回
        return "按照不符合業(yè)務邏輯處理";
    }
}
  • 自定義 GatewayFilter:GatewayFilter 具體的實現(xiàn)方式是工廠,每個工廠都繼承了 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è)務邏輯,繼續(xù)執(zhí)行下一個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)啟動階段

  • Yaml 文件和 GatewayProperties 文件映射,映射處理源碼在 JavaBeanBinder.BeanProperty#getValue –> CollectionBinder#merge —> Binder#bindBean;
  • 加載 Locator Bean,為后續(xù)讀取 RouteDefinition 做準備【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方法中實現(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<>();
		// 如果默認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);
			// 每一個工廠中都有一個靜態(tài)內(nèi)部類Config,目的是存儲我們設(shè)置的Filter值
			Object configuration = factory.newConfig();
			// 將后幾個參數(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;
	}
}

請求處理階段

  • ReactorHttpHandlerAdapter#apply 方法是請求到網(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 {
			// 獲取請求的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ù)請求的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 請求處理器/控制器的中央分發(fā)處理器,把請求分發(fā)給已經(jīng)注冊的處理程序處理,DispatcherHandler 遍歷 Mapping 獲取對應的 handler,網(wǎng)關(guān)一共有 6 個 handlerMapping【此處會找到 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)啟動時進行了初始化
	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 獲取我們在配置我文件中配置的 Route,和當前請求的路由做匹配;
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
	protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		// routeLocator獲取我們在配置我文件中配置的Route
		return this.routeLocator.getRoutes()
				.concatMap(route -> Mono.just(route).filterWhen(r -> {
					exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
					// 當前請求的路由做匹配
					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原理深度解析的詳細內(nèi)容,更多關(guān)于SpringCloud Gateway原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

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

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

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

    為什么說要慎用SpringBoot @ComponentScan

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

    Java生成PDF文件的實例代碼

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

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

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

    Elasticsearch學習之Terms?set?查詢

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

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

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

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

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

    Spring底層核心源碼原理解析

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

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

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

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

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

最新評論