FilterDefinition转换成Filter的过程

FilterDefinition转换成Filter的过程

  • 路由配置示例
  • FilterDefinition转换成Filter的过程
  • 核心点

路由配置示例

Spring Cloud Gateway支持通过Filter实现令牌桶限流。通过YAML的路由配置示例如下:

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend
          filters:
          - name: RequestRateLimiter
            args:
              rate-limiter: "#{customRateLimiter}"
              key-resolver: "#{customKeyResolver}"
              redis-rate-limiter.replenishRate: 500
              redis-rate-limiter.burstCapacity: 1000
              redis-rate-limiter.requestedTokens: 1

FilterDefinition转换成Filter的过程

本文主要介绍Spring Cloud Gateway是如何将YAML配置转换成最终的GatewayFilter进行执行限流操作的。下图是以限流Filter为例,介绍如何根据FilterDefinition生成GatewayFilter。

图中颜色的含义:绿色表示单例、蓝色表示多例。
FilterDefinition转换成Filter的过程_第1张图片

  1. 事前准备:从Spring容器中查找所有的GatewayFilterFactory类型的bean缓存到Map中;
  2. FilterDefinition中包含两个字段:name和args。
  • name用来获取GatewayFilterFactory,如name为RequestRateLimiter,则对应的GatewayFilterFactory为RequestRateLimiter-GatewayFilterFactory。
  • args参数有两个用途,一个是用于配置GatewayFilter,另一个用于配置GatewayFilter的内部bean。
  1. 构建GatewayFilterFactory配置对象,对RequestRateLimiter-GatewayFilterFactory来讲,可配置项主要是KeyResolverRateLimiter两个,可以通过#{bean-name}的方式引入Bean。
rate-limiter: "#{redisRateLimiter}"
key-resolver: "#{customKeyResolver}"
  1. 基于GatewayFilterFactory配置对象生成GatewayFilter。RequestRateLimiterGatewayFilterFactory的apply方法生成GatewayFilter。
@Override
public GatewayFilter apply(Config config) {
	KeyResolver resolver = getOrDefault(config.keyResolver, defaultKeyResolver);
	RateLimiter<Object> limiter = getOrDefault(config.rateLimiter,
			defaultRateLimiter);
	boolean denyEmpty = getOrDefault(config.denyEmptyKey, this.denyEmptyKey);
	HttpStatusHolder emptyKeyStatus = HttpStatusHolder
			.parse(getOrDefault(config.emptyKeyStatus, this.emptyKeyStatusCode));

	return (exchange, chain) -> resolver.resolve(exchange).defaultIfEmpty(EMPTY_KEY)
			.flatMap(key -> {
				if (EMPTY_KEY.equals(key)) {
					if (denyEmpty) {
						setResponseStatus(exchange, emptyKeyStatus);
						return exchange.getResponse().setComplete();
					}
					return chain.filter(exchange);
				}
				return limiter.isAllowed(config.getRouteId(), key)
						.flatMap(response -> {

							for (Map.Entry<String, String> header : response
									.getHeaders().entrySet()) {
								exchange.getResponse().getHeaders()
										.add(header.getKey(), header.getValue());
							}

							if (response.isAllowed()) {
								return chain.filter(exchange);
							}

							setResponseStatus(exchange, config.getStatusCode());
							return exchange.getResponse().setComplete();
						});
			});
}
  1. 在创建完GatewayFilter后,会发布FilterArgsEvent事件,该事件通过Spring的事件机制传递给Listener们。此处对应的Listener为RedisRateLimiter的单例Bean,其参数配置如下:
redis-rate-limiter.replenishRate: 500
redis-rate-limiter.burstCapacity: 1000
redis-rate-limiter.requestedTokens: 1
  1. RedisRateLimiter接收到事件后判定是否需要处理该事件(通过配置的前缀redis-rate-limiter判定,前缀在RedisRateLimiter类中有定义),如果是该Bean的配置则创建RedisRateLimiter.Config对象。
  2. 将配置对象缓存到Map。Key为Route ID,Value为RedisRateLimiter.Config对象。

至此,GatewayFilter创建完毕。

核心点

  1. 核心处理流程和个性化配置的分离。
  • RequestRateLimiter-GatewayFilterFactory的apply方法包含了核心的限流处理逻辑,但Key的生成规则和限流策略的具体实现却交由用户自行实现。
  • 如RedisRateLimiter提供了令牌桶算法的核心处理逻辑,但具体到每一个路由的replenishRate和burstCapacity则交由用户配置实现。
  1. 巧妙利用Spring的事件机制处理GatewayFilterFactory.Config注入Bean的属性配置问题。
  2. 单例和多例的结合运用。
  • RequestRateLimiterGatewayFilterFactory为单例,RequestRateLimiterGatewayFilterFactory.Config为多例,最终创建的RequestRateLimiterGatewayFilter为多例。
  • RedisRateLimiter为单例,具体的RedisRateLimiter.Config为多例。

你可能感兴趣的:(Spring,Cloud,限流,spring,cloud,RateLimiter)