springboot整合springboot alibaba gateway 整合redis
时间: 2023-10-08 12:12:45 浏览: 110
以下是Spring Boot整合Spring Cloud Alibaba Gateway并使用Redis进行缓存的步骤:
1. 创建Spring Boot工程,添加依赖
在pom.xml文件中添加以下依赖:
```
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
```
2. 配置Redis
在application.properties文件中添加以下配置:
```
spring.redis.host=127.0.0.1
spring.redis.port=6379
```
3. 配置Gateway
在application.yml文件中添加以下配置:
```
spring:
cloud:
gateway:
routes:
- id: test_route
uri: http://localhost:8080
predicates:
- Path=/test/**
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
user:
rate-limiter:
redis:
prefix: "rate-limiter"
remaining-key: "remaining"
reset-key: "reset"
```
其中:
- id:路由ID
- uri:目标服务的URL
- predicates:路由断言,此处表示只有访问/test/**的请求才会被路由到目标服务
- filters:路由过滤器,此处使用了RequestRateLimiter过滤器,用于限流
4. 编写Redis限流过滤器
在工程中创建一个RedisRatelimiterFilter类,实现GatewayFilter和Ordered接口,并重写filter方法。
```
@Component
public class RedisRatelimiterFilter implements GatewayFilter, Ordered {
private final RedisTemplate<String, String> redisTemplate;
private final StringRedisTemplate stringRedisTemplate;
private final ObjectMapper objectMapper;
public RedisRatelimiterFilter(RedisTemplate<String, String> redisTemplate,
StringRedisTemplate stringRedisTemplate,
ObjectMapper objectMapper) {
this.redisTemplate = redisTemplate;
this.stringRedisTemplate = stringRedisTemplate;
this.objectMapper = objectMapper;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String key = "rate-limiter:" + exchange.getRequest().getPath().value();
String remainingKey = key + ":remaining";
String resetKey = key + ":reset";
return redisTemplate.execute(script, Collections.singletonList(remainingKey), "1", "2")
.flatMap(result -> {
String json = objectMapper.writeValueAsString(result);
Map<String, Object> map = objectMapper.readValue(json, Map.class);
int remaining = (int) map.get("remaining");
long reset = (long) map.get("reset");
exchange.getResponse().getHeaders().add("X-RateLimit-Remaining", String.valueOf(remaining));
exchange.getResponse().getHeaders().add("X-RateLimit-Reset", String.valueOf(reset));
if (remaining < 0) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return stringRedisTemplate.opsForValue().increment(remainingKey)
.flatMap(result2 -> {
if (result2.equals(1L)) {
stringRedisTemplate.expire(resetKey, Duration.ofMinutes(1));
}
return chain.filter(exchange);
});
});
}
private static final RedisScript<List<Long>> script = RedisScript.of(
"local key = KEYS[1]\n" +
"local now = tonumber(ARGV[1])\n" +
"local rate = tonumber(ARGV[2])\n" +
"local capacity = tonumber(ARGV[3])\n" +
"local remaining = redis.call('get', key)\n" +
"if remaining then\n" +
" remaining = tonumber(remaining)\n" +
"else\n" +
" remaining = capacity\n" +
"end\n" +
"if remaining == 0 then\n" +
" return {0, 0}\n" +
"else\n" +
" local reset\n" +
" if remaining == capacity then\n" +
" reset = now + 60\n" +
" redis.call('set', key..\":reset\", reset)\n" +
" else\n" +
" reset = tonumber(redis.call('get', key..\":reset\"))\n" +
" end\n" +
" local ttl = reset - now\n" +
" local ratePerMillis = rate / 1000\n" +
" local permits = math.min(remaining, ratePerMillis * ttl)\n" +
" redis.call('set', key, remaining - permits)\n" +
" return {permits, reset}\n" +
"end\n",
ReturnType.MULTI,
Collections.singletonList("remaining")
);
@Override
public int getOrder() {
return -1;
}
}
```
5. 编写KeyResolver
在工程中创建一个UserKeyResolver类,实现KeyResolver接口,并重写resolve方法。
```
@Component
public class UserKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
String userId = exchange.getRequest().getQueryParams().getFirst("userId");
return Mono.justOrEmpty(userId);
}
}
```
6. 测试
启动工程,访问http://localhost:8080/test,可以看到返回结果为“Hello, world!”;再次访问http://localhost:8080/test,可以看到返回结果为“Too Many Requests”。
以上就是Spring Boot整合Spring Cloud Alibaba Gateway并使用Redis进行缓存的步骤。
阅读全文