gateway 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
redis 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
配置文件
spring:
application:
name: gateway-limit
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: test-ip
# 转发的服务名称
uri: lb://test-ip
# 请求路径
predicates:
- Path=/test-ip/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter:
replenishRate: 1
burstCapacity: 2
key-resolver: '#{@ipKeyResolver}'
这个依赖正常启动,但是 spring-boot-starter-data-redis-reactive 默认使用的 redis client 是 lettuce,这个在连接网络时会有问题
如何通过客户端程序连接Redis_云数据库 Redis 版-阿里云帮助中心
连接最后有介绍
所以改成了 jedis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<exclusions>
<exclusion>
<artifactId>lettuce-core</artifactId>
<groupId>io.lettuce</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在连接过程中也是有问题,最终源码打断点跟到了 LettuceConnectionFactory 和 JedisConnectionFactory,发现 LettuceConnectionFactory 加了一个接口 ReactiveRedisConnectionFactory,而 JedisConnectionFactory 没有,导致了这个问题。
public class LettuceConnectionFactory
implements InitializingBean, DisposableBean, RedisConnectionFactory, ReactiveRedisConnectionFactory {
public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
package org.springframework.cloud.gateway.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.DispatcherHandler;
@Configuration
@AutoConfigureAfter(RedisReactiveAutoConfiguration.class)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@ConditionalOnBean(ReactiveRedisTemplate.class)
@ConditionalOnClass({ RedisTemplate.class, DispatcherHandler.class })
class GatewayRedisAutoConfiguration {
@Bean
@SuppressWarnings("unchecked")
public RedisScript redisRequestRateLimiterScript() {
DefaultRedisScript redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(
new ClassPathResource("META-INF/scripts/request_rate_limiter.lua")));
redisScript.setResultType(List.class);
return redisScript;
}
@Bean
// TODO: replace with ReactiveStringRedisTemplate in future
public ReactiveRedisTemplate<String, String> stringReactiveRedisTemplate(
ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
RedisSerializer<String> serializer = new StringRedisSerializer();
RedisSerializationContext<String, String> serializationContext = RedisSerializationContext
.<String, String>newSerializationContext().key(serializer)
.value(serializer).hashKey(serializer).hashValue(serializer).build();
return new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory,
serializationContext);
}
@Bean
@ConditionalOnMissingBean
public RedisRateLimiter redisRateLimiter(
ReactiveRedisTemplate<String, String> redisTemplate,
@Qualifier(RedisRateLimiter.REDIS_SCRIPT_NAME) RedisScript<List<Long>> redisScript,
Validator validator) {
return new RedisRateLimiter(redisTemplate, redisScript, validator);
}
}
gateway 与 redis 的自动装配类 GatewayRedisAutoConfiguration 中需要 ReactiveRedisConnectionFactory 这个 bean。
由此得知,还是使用 redis 默认的客户端。jedis 不支持响应式连接。