【Spring Cloud Gateway专题】二、核心组件初始化步骤及请求流程

1、前言

在当下学习和使用 spring cloud 技术栈的热潮中,网关已经成了不可或缺的内容。开发者在选择用来解决特定领域内问题的框架时,多了解几款相关同类产品可加大选择余地。除了 Netflix 的 zuul 之外,spring cloud gateway 可作为开发者的另一个选择。
Zuul 分 1.x 和 2.x 版本。Zuul 2.x 版本和 spring cloud gateway 都使用 Non-Blocking I/O 模型。
——节选自“https://mp.weixin.qq.com/s/jCQR1WkOsiOzozMAeIPk3g 「欧文雪」”
文章多参考
「欧文雪」:https://mp.weixin.qq.com/s/jCQR1WkOsiOzozMAeIPk3g
芋道源码http://www.iocoder.cn/categories/Spring-Cloud-Gateway/

1.1 Gateway 技术栈

开发者了解以下技术,学习 gateway 会更加容易。
① project reactor,遵循 Reactive Streams Specification,使用非阻塞编程模型。
② webflux,基于 spring 5.x 和 reactor-netty 构建,不依赖于 Servlet 容器,但是可以在支持 Servlet 3.1 Non-Blocking IO API 的容器上运行。

1.2 Gateway 工作机制

Spring cloud gateway 的工作机制大体如下:
① Gateway 接收客户端请求。
② 客户端请求与路由信息进行匹配,匹配成功的才能够被发往相应的下游服务。
③ 请求经过 Filter 过滤器链,执行 pre 处理逻辑,如修改请求头信息等。
④ 请求被转发至下游服务并返回响应。
⑤ 响应经过 Filter 过滤器链,执行 post 处理逻辑。
⑥ 向客户端响应应答。
Gateway 工作机制可参考下图(图片来自官方文档):
在这里插入图片描述
本文主要介绍 spring cloud gateway 核心组件的初始化步骤。然后,描述当一个外部请求获取后,经过的处理流程。

2、核心组件

2.1 最核心组件 Route

(1) Route

Route 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。
Route源代码:

public class Route implements Ordered {

    private final String id; // ①

    private final URI uri; // ②

    private final int order; // ③

    private final AsyncPredicate<ServerWebExchange> predicate; // ④

    private final List<GatewayFilter> gatewayFilters; // ⑤

Route 主要定义了如下几个部分:

① id,标识符,区别于其他 Route。

② destination uri,路由指向的目的地 uri,即客户端请求最终被转发的目的地。

③ order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。

④ predicate,谓语,表示匹配该 Route 的前置条件,即满足相应的条件才会被路由到目的地 uri。

⑤ gateway filters,过滤器用于处理切面逻辑,如路由转发前修改请求头等。

(2) AsyncPredicate

Predicate 即 Route 中所定义的部分,用于条件匹配,请参考 Java 8 提供的 Predicate 和 Function。
AsyncPredicate源代码:

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {

    default AsyncPredicate<T> and(AsyncPredicate<? super T> other) { // ①
        Objects.requireNonNull(other, "other must not be null");
        return t -> Flux.zip(apply(t), other.apply(t))
                .map(tuple -> tuple.getT1() && tuple.getT2());
    }

    default AsyncPredicate<T> negate() { // ②
        return t -> Mono.from(apply(t)).map(b -> !b);
    }

    default AsyncPredicate<T> or(AsyncPredicate<? super T> other) { // ③
        Objects.requireNonNull(other, "other must not be null");
        return t -> Flux.zip(apply(t), other.apply(t))
                .map(tuple -> tuple.getT1() || tuple.getT2());
    }
}

AsyncPredicate 定义了 3 种逻辑操作方法:

① and ,与操作,即两个 Predicate 组成一个,需要同时满足。

② negate,取反操作,即对 Predicate 匹配结果取反。

③ or,或操作,即两个 Predicate 组成一个,只需满足其一。

(3) GatewayFilter

很多框架都有 Filter 的设计,用于实现可扩展的切面逻辑。
GatewayFilter 源代码:

public interface GatewayFilter extends ShortcutConfigurable {

    String NAME_KEY = "name";
    String VALUE_KEY = "value";

    /**
     * Process the Web request and (optionally) delegate to the next
     * {@code WebFilter} through the given {@link GatewayFilterChain}.
     * @param exchange the current server exchange
     * @param chain provides a way to delegate to the next filter
     * @return {@code Mono<Void>} to indicate when request processing is complete
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

Filter 最终是通过 filter chain 来形成链式调用的,每个 filter 处理完 pre filter 逻辑后委派给 filter chain,filter chain 再委派给下一下 filter。

GatewayFilterChain 源代码:

public interface GatewayFilterChain {

    /**
     * Delegate to the next {@code WebFilter} in the chain.
     * @param exchange the current server exchange
     * @return {@code Mono<Void>} to indicate when request handling is complete
     */
    Mono<Void> filter(ServerWebExchange exchange);

}

2.2 如何构建 Route

如何构建 Route 组件?Spring 提供了两种方式:外部化配置和编程的方式。

(1) 外部化配置

Spring cloud gateway 提供了一些开箱即用的 Predicate 和 Filter,它们通过工厂模式来生产。
下面这个例子由官方文档中的两个示例组合而成。

spring:
  cloud:
    gateway: # ①
      routes: # ②
      - id: cookie_route # ③
        uri: http://example.org # ④
        predicates: # ⑤
        - Cookie=chocolate, ch.p # ⑥
        filters: # ⑦
        - AddRequestHeader=X-Request-Foo, Bar # ⑧

详细说明:

① “spring.cloud.gateway” 为固定前缀。

② 定义路由信息列表,即可定义多个路由。

③ 声明了一个 id 为 “cookie_route” 的路由。

④ 定义了路由的目的地 uri,即请求转发的目的地。

⑤ 声明 predicates,即请求满足相应的条件才能匹配成功。

⑥ 定义了一个 Predicate,当名称为 chocolate 的 Cookie 的值匹配ch.p时 Predicate 才能够匹配,它由 CookieRoutePredicateFactory 来生产。

⑦ 声明 filters,即路由转发前后处理的过滤器。

⑧ 定义了一个 Filter,所有的请求转发至下游服务时会添加请求头 X-Request-Foo:Bar ,由AddRequestHeaderGatewayFilterFactory 来生产。

(2) 编程方式

开发者还可以通过编程的方式来定义 Route,编程的方式会更加灵活。
下面通过 fluent API RouteLocatorBuilder 来构建 RouteLocator。
示例(根据官方文档改造):

// static imports from GatewayFilters and RoutePredicates
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { // ①
    return builder.routes() // ②
            .route(r -> r.host("**.abc.org").and().path("/image/png") // ③
                .filters(f ->
                        f.addResponseHeader("X-TestHeader", "foobar")) // ④
                .uri("http://httpbin.org:80") // ⑤
            )
            .build();
}

① RouteLocatorBuilder bean 在 spring-cloud-starter-gateway 模块自动装配类中已经声明,可直接使用。RouteLocator 封装了对 Route 获取的定义,可简单理解成工厂模式。

② RouteLocatorBuilder 可以构建多个路由信息。

③ 指定了 Predicates,这里包含两个:
请求头Host需要匹配**.abc.org,通过 HostRoutePredicateFactory 产生。
请求路径需要匹配/image/png,通过 PathRoutePredicateFactory 产生。

④ 指定了一个 Filter,下游服务响应后添加响应头X-TestHeader:foobar,通过AddResponseHeaderGatewayFilterFactory 产生。

⑤ 指定路由转发的目的地 uri。

如果说外部化配置完全是个黑盒,那么通过编程的方式使开发者向白盒靠近了一步。因为开发者需要使用 gateway 的 api,需要开发者对其有工作机制有所了解。

2.3 Route 构建的原理

产生Route的两种方式包括外部化配置方式和自定义编程方式,下图展示了这两种方式。
在这里插入图片描述
通过自定义RouteLocator方式构建,直接由开发者通过工厂方法RouteLocatorBuilder产生一个Route。故不再细解。本节重点讲通过外部化配置方式构建。

(1) 通过RouteDefinition构建

外部化配置方式由RouteDefinitionLocator产生RouteDefinition,再由RouteDefinitionRouteLocator将RouteDefinition转换为Route。其中,外部化配置方式除了上文中提到的配置文件方式(PropertiesRouteDefinitionLocator)外,还包括RouteDefinitionRepository、DiscoveryClientRouteDefinitionLocator(通过注册中心发现)。
关于RouteDefinitionRouteLocator如何将RouteDefinition转换为Route,请参考芋道源码route-locator-route-definition

(2) RouteDefinition

这里需要先介绍RouteDefinition类,RouteDefinition类定义了外部化配置参数的类,它会被转化为Route。RouteDefinition 源码如下:

public class RouteDefinition {
    @NotEmpty
    private String id = UUID.randomUUID().toString(); // ①

    @NotEmpty
    @Valid
    private List<PredicateDefinition> predicates = new ArrayList<>();  // ②

    @Valid
    private List<FilterDefinition> filters = new ArrayList<>();  // ③

    @NotNull
    private URI uri;  // ④

    private int order = 0; // ⑤
}

① 定义 Route 的 id,默认使用 UUID。

② 定义 Predicate。

③ 定义 Filter。

④ 定义目的地 URI。

⑤ 定义 Route 的序号。

可见,RouteDefinition 中所定义的属性与 Route 本身是一一对应的。

(3) FilterDefinition

同样遵循组件名前缀 + Definition 后缀的命名规范,用于定义 Filter。

public class FilterDefinition {
    @NotNull
    private String name; // ①
    private Map<String, String> args = new LinkedHashMap<>(); // ②

① 定义了 Filter 的名称,符合特定的命名规范,为对应的工厂名前缀。

② 一个键值对参数用于构造 Filter 对象。

外部配置到 FilterDefinition 对象绑定
以 AddRequestHeader GatewayFilter Factory 为例:

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://example.org
        filters:
        - AddRequestHeader=X-Request-Foo, Bar # ①

① 这一行配置被 spring 解析后会绑定到一个 FilterDefinition 对象。

AddRequestHeader ,对应 FilterDefinition 中的 name 属性。
X-Request-Foo, Bar ,会被解析成 FilterDefinition 中的 Map 类型属性 args。此处会被解析成两组键值对,以英文逗号将=后面的字符串分隔成数组,key是固定字符串 genkey + 数组元素下标,value为数组元素自身。
相关源码:

// FilterDefinition 构造函数
public FilterDefinition(String text) {
    int eqIdx = text.indexOf("=");
    if (eqIdx <= 0) {
        setName(text);
        return;
    }
    setName(text.substring(0, eqIdx));
    String[] args = tokenizeToStringArray(text.substring(eqIdx+1), ",");
    for (int i=0; i < args.length; i++) {
        this.args.put(NameUtils.generateName(i), args[i]); // ①
    }
}

// ① 使用到的工具类 NameUtils 源码

public class NameUtils {
    public static final String GENERATED_NAME_PREFIX = "_genkey_";
    public static String generateName(int i) {
        return GENERATED_NAME_PREFIX + i;
    }
}

(4) PredicateDefinition

同样遵循组件名前缀 + Definition 后缀的命名规范,用于定义 Predicate。

public class PredicateDefinition {
    @NotNull
    private String name; // ①
    private Map<String, String> args = new LinkedHashMap<>(); // ②

① 定义了 Predicate 的名称,它们要符固定的命名规范,为对应的工厂名称。

② 一个 Map 类型的参数,构造 Predicate 使用到的键值对参数。
外部化配置绑定到 PredicateDefinition 源码逻辑与 FilterDefinition 类似,不再赘述。

2.4 框架初始化步骤

Spring boot 遵循规约大于配置的原则,starter 模块都有对应的以模块名称作前缀,以 “AutoConfiguration” 后缀的自动装配类。同样的还有以模块名前缀,以Properties后缀的配置类作为支持。Gateway 模块自动装配类及对应的配置类参考:
在这里插入图片描述
在官方提供的实例项目 spring-cloud-gateway-sample ,我们看到 GatewaySampleApplication 上有 @EnableAutoConfiguration 注解。因为该项目导入了 spring-cloud-gateway-core 依赖库,它会扫描 Spring Cloud Gateway 的配置。(注意,我们的应用中,可能使用了@SpringBootApplication注解,该注解包含@EnableAutoConfiguration注解)
网关初始化步骤参考:芋道源码 网关初始化

3、请求流程

3.1 网关请求步骤

我们一起来看看,一个请求是怎么被 Spring Cloud Gateway 处理的,如下图 :
在这里插入图片描述
转换为官方的图:
在这里插入图片描述
org.springframework.web.reactive.DispatcherHandler :接收到请求,匹配 HandlerMapping ,此处会匹配到 RoutePredicateHandlerMapping 。
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping :接收到请求,匹配 Route 。
org.springframework.cloud.gateway.handler.FilteringWebHandler :获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求。

3.2 DispatcherHandler

org.springframework.web.reactive.DispatcherHandler ,请求分发处理器,Spring WebFlux 的访问入口。可能大多数人对这个类都比较陌生,我们来看看他在 Spring MVC 的兄弟 DispatcherServlet 是不是就有点熟悉的感觉。

下面来看看 DispatcherHandler#handle(ServerWebExchange) 方法,代码如下 :

1: public class DispatcherHandler implements WebHandler, ApplicationContextAware {
 2: 
 3: 	@Nullable
 4: 	private List<HandlerMapping> handlerMappings;
 5: 
 6: 	@Nullable
 7: 	private List<HandlerAdapter> handlerAdapters;
 8: 
 9: 	@Override
10: 	public Mono<Void> handle(ServerWebExchange exchange) {
11: 		if (logger.isDebugEnabled()) {
12: 			ServerHttpRequest request = exchange.getRequest();
13: 			logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
14: 		}
15: 		if (this.handlerMappings == null) {
16: 			return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
17: 		}
18: 		return Flux.fromIterable(this.handlerMappings)
19: 				.concatMap(mapping -> mapping.getHandler(exchange))
20: 				.next()
21: 				.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
22: 				.flatMap(handler -> invokeHandler(exchange, handler))
23: 				.flatMap(result -> handleResult(exchange, result));
24: 	}
25: }

第 18 至 20 行 :顺序使用 handlerMappings 获得对应的 WebHandler 。
使用 #concatMap(Function) 操作符的原因是考虑 handlerMappings 的顺序性,具体作用是将所有handlermapping按照顺序组合起来 。然后,遍历所有handlermapping,找到公共抽象类AbstractHandlerMapping,该类有getHandler(ServerWebExchange exchange)方法,该方法会调用所有HandlerMapping的getHandlerInternal方法(目前发现只有RouterFunctionMapping和RoutePredicateHandlerMapping有该方法)。
使用官方 spring-cloud-gateway-sample 项目,此处打断点,handlerMappings 变量值如下图 :
在这里插入图片描述
第 19 行,调用 HandlerMapping#getHandler(ServerWebExchange) 获得 Handler 。在整理,RoutePredicateHandlerMapping 匹配请求对应的 Route ,并返回 FilteringWebHandler 。此时,FilteringWebHandler 还并未获得 Route 的 GatewayFilter ,创建 GatewayFilterChain 处理请求。

第 21 行 :如果匹配不到 WebHandler ,返回 HANDLER_NOT_FOUND_EXCEPTION 。

第 22 行 :调用 #handle() 方法,执行 Handler 。代码如下 :

 1: private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
 2: 	if (this.handlerAdapters != null) {
 3: 		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
 4: 			if (handlerAdapter.supports(handler)) {
 5: 				return handlerAdapter.handle(exchange, handler);
 6: 			}
 7: 		}
 8: 	}
 9: 	return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
10: }

使用官方 spring-cloud-gateway-sample 项目,此处打断点,handlerMappings 变量值如下图 :
在这里插入图片描述
第 2 至 8 行 :顺序匹配 HandlerAdapter ,通过调用 HandlerAdapter#handle(ServerWebExchange, Object) 方法,从而执行 Handler 。在此处,我们会匹配到 SimpleHandlerAdapter 。
第 9 行 :匹配不到 HandlerAdapter ,返回 IllegalStateException 。
第 23 行 :调用 #handleResult() 方法,处理结果。SimpleHandlerAdapter 返回的是 Mono.empty() ,所以不会触发该方法。#handleResult() 代码如下 :

1: private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
2: 	return getResultHandler(result).handleResult(exchange, result)
3: 			.onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult ->
4: 					getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
5: }

3.3 SimpleHandlerAdapter

org.springframework.web.reactive.result.SimpleHandlerAdapter ,执行 WebHandler 的处理器适配器。
#handle(ServerWebExchange, Object) 方法,代码如下 :

1: @Override
2: public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
3: 	WebHandler webHandler = (WebHandler) handler;
4: 	Mono<Void> mono = webHandler.handle(exchange);
5: 	return mono.then(Mono.empty());
6: }

第 3 至 4 行 :调用 WebHandler#handle(ServerWebExchange) 方法,执行处理器。例如,WebHandler 为 FilteringWebHandler 时,获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求。
第 5 行 :在 WebHandler 执行完后 ( #then(Mongo) ),然后返回 Mono.empty() 。

3.4 RoutePredicateHandlerMapping

org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping ,匹配 Route ,并返回处理 Route 的 FilteringWebHandler 。

RoutePredicateHandlerMapping 构造方法,代码如下 :

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {

	private final FilteringWebHandler webHandler;
	private final RouteLocator routeLocator;

	public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator) {
		this.webHandler = webHandler;
		this.routeLocator = routeLocator;

		setOrder(1); // RequestMappingHandlerMapping 之后
	}
}

调用 #setOrder(1) 的原因,Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要经过网关,它通过 RequestMappingHandlerMapping 进行请求匹配处理。RequestMappingHandlerMapping 的 order = 0 ,需要排在 RoutePredicateHandlerMapping 前面。所以,RoutePredicateHandlerMapping 设置 order = 1 。
#getHandlerInternal() 方法,在 DispatcherHandler#handle(ServerWebExchange) 方法的【第 19 行】被调用,匹配 Route ,并返回处理 Route 的 FilteringWebHandler 。代码如下 :

 1: @Override
 2: protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
 3:     // 设置 GATEWAY_HANDLER_MAPPER_ATTR 为 RoutePredicateHandlerMapping
 4: 	exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().getSimpleName());
 5: 
 6: 	return lookupRoute(exchange) // 匹配 Route
 7: 			// .log("route-predicate-handler-mapping", Level.FINER) //name this
 8: 			.flatMap((Function<Route, Mono<?>>) r -> { // 返回 FilteringWebHandler
 9: 				if (logger.isDebugEnabled()) {
10: 					logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r);
11: 				}
12: 
13: 				// 设置 GATEWAY_ROUTE_ATTR 为 匹配的 Route
14: 				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
15: 				// 返回
16: 				return Mono.just(webHandler);
17: 			}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { // 匹配不到 Route
18: 				if (logger.isTraceEnabled()) {
19: 					logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");
20: 				}
21: 			})));
22: }

第 4 行 :设置 GATEWAY_HANDLER_MAPPER_ATTR 为 RoutePredicateHandlerMapping 。
第 6 行 :调用 #lookupRoute(ServerWebExchange) 方法,匹配 Route 。
第 8 至 16 行 :返回 Route 的处理器 FilteringWebHandler 。
第 14 行 :设置 GATEWAY_ROUTE_ATTR 为匹配的 Route 。
第 16 行 :返回 FilteringWebHandler。
第 17 至 21 行 :匹配不到 Route ,返回 Mono.empty() ,即不返回处理器。这样会不会有问题?不会,在 DispatcherHandler#handle(ServerWebExchange) 方法的【第 21 行】,我们可以看到,当没有合适的 Handler ,返回 Mono.error(HANDLER_NOT_FOUND_EXCEPTION) 。
#lookupRoute(ServerWebExchange) 方法,顺序匹配 Route 。代码如下 :

 1: protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
 2: 	return this.routeLocator.getRoutes()
 3: 			.filter(route -> route.getPredicate().test(exchange))
 4: 			.next()
 5: 			//TODO: error handling
 6: 			.map(route -> {
 7: 				if (logger.isDebugEnabled()) {
 8: 					logger.debug("RouteDefinition matched: " + route.getId());
 9: 				}
10: 				validateRoute(route, exchange);
11: 				return route;
12: 			});
13: }

第 2 至 4 行 :调用 RouteLocator#getRoutes() 方法,获得全部 Route ,并调用 Predicate#test(ServerWebExchange) 方法,顺序匹配一个 Route。
第 5 行 :未来会增加匹配过程中发生异常的处理。目前,任何一个 Predicate#test(ServerWebExchange) 的方法调用发生异常时,都会导致匹配不到 Route 。一定要注意。
第 6 至 11 行 :调用 #validateRoute(Route, ServerWebExchange) 方法,校验 Route 的有效性。目前该方法是个空方法,可以通过继承 RoutePredicateHandlerMapping 进行覆盖重写。

3.5 FilteringWebHandler

在 SimpleHandlerAdapter 里,我们看到 SimpleHandlerAdapter#handle(ServerWebExchange, Object) 调用 FilteringWebHandler#handle(ServerWebExchange) 方法,处理请求。
FilteringWebHandler 通过创建请求对应的 Route 对应的 GatewayFilterChain 进行处理。
org.springframework.cloud.gateway.handler.FilteringWebHandler ,#handle(ServerWebExchange) 代码如下 :

1: public class FilteringWebHandler implements WebHandler {
 2: 
 3: 	/**
 4: 	 * 全局过滤器
 5: 	*/
 6: 	private final List<GatewayFilter> globalFilters;
 7: 
 8: 	@Override
 9: 	public Mono<Void> handle(ServerWebExchange exchange) {
10: 	    // 获得 Route
11: 		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
12: 		// 获得 GatewayFilter
13: 		List<GatewayFilter> gatewayFilters = route.getFilters();
14: 		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
15: 		combined.addAll(gatewayFilters);
16: 
17: 		// 排序
18: 		//TODO: needed or cached?
19: 		AnnotationAwareOrderComparator.sort(combined);
20: 		logger.debug("Sorted gatewayFilterFactories: "+ combined);
21: 
22: 		// 创建 DefaultGatewayFilterChain
23: 		return new DefaultGatewayFilterChain(combined).filter(exchange);
24: 	}
25: }

本方法涉及到的过滤器 GlobalFilter / GatewayFilter / GatewayFilterAdapter / OrderedGatewayFilter 类,参考芋道源码《Spring-Cloud-Gateway 源码解析 —— 过滤器 (4.1) 之 GatewayFilter 一览》 详细解析。
第 11 行 :从 GATEWAY_ROUTE_ATTR 获得 请求对应的 Route 。
第 13 至 15 行 :获得 GatewayFilter 数组,包含 route.filters 和 globalFilters 。
第 19 行 :排序获得的 GatewayFilter 数组。
第 23 行 :使用获得的 GatewayFilter 数组创建 DefaultGatewayFilterChain ,过滤处理请求。

©️2020 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值