mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 02:08:15 +08:00
网关使用Redis存储路由信息
This commit is contained in:
parent
7da40951e7
commit
71a58178eb
@ -20,26 +20,23 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- pool 对象池 -->
|
||||
<!--<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
package com.ruoyi.gateway.config;
|
||||
|
||||
import com.ruoyi.gateway.config.provider.ComplexRouteDefinitionRepository;
|
||||
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
||||
import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -21,10 +20,13 @@ import javax.annotation.Resource;
|
||||
* @date 2021-09-11
|
||||
*/
|
||||
@Configuration
|
||||
public class GatewayConfig {
|
||||
public class GatewayConfig
|
||||
{
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, RouteDefinition> redisTemplate;
|
||||
@Resource
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, RouteDefinition> redisTemplate(RedisConnectionFactory redisConnectionFactory)
|
||||
@ -40,29 +42,14 @@ public class GatewayConfig {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouteDefinitionRepository complexRouteDefinitionRepository()
|
||||
{
|
||||
return new ComplexRouteDefinitionRepository(inMemoryRouteDefinitionRepository(), redisRouteDefinitionRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
* 内存 路由仓库
|
||||
*
|
||||
* @return 本地内存路由仓库
|
||||
*/
|
||||
RouteDefinitionRepository inMemoryRouteDefinitionRepository()
|
||||
{
|
||||
return new InMemoryRouteDefinitionRepository();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis 路由仓库
|
||||
*
|
||||
* @return redis路由仓库
|
||||
*/
|
||||
RouteDefinitionRepository redisRouteDefinitionRepository()
|
||||
@Bean
|
||||
public RouteDefinitionRepository redisRouteDefinitionRepository()
|
||||
{
|
||||
return new RedisRouteDefinitionRepository(redisTemplate);
|
||||
return new RedisRouteDefinitionRepository(redissonClient);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
package com.ruoyi.gateway.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.ruoyi.gateway.config.provider.RedissonProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.codec.JsonJacksonCodec;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* redis配置
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
private static final String REDIS_PROTOCOL_PREFIX = "redis://";
|
||||
private static final String REDISS_PROTOCOL_PREFIX = "rediss://";
|
||||
|
||||
@Autowired
|
||||
private RedisProperties redisProperties;
|
||||
|
||||
@Autowired
|
||||
private RedissonProperties redissonProperties;
|
||||
|
||||
@Bean(destroyMethod = "shutdown")
|
||||
@ConditionalOnMissingBean(RedissonClient.class)
|
||||
public RedissonClient redisson() throws IOException {
|
||||
String prefix = REDIS_PROTOCOL_PREFIX;
|
||||
if (redisProperties.isSsl()) {
|
||||
prefix = REDISS_PROTOCOL_PREFIX;
|
||||
}
|
||||
Config config = new Config();
|
||||
config.setThreads(redissonProperties.getThreads())
|
||||
.setNettyThreads(redissonProperties.getNettyThreads())
|
||||
.setCodec(JsonJacksonCodec.INSTANCE)
|
||||
.setTransportMode(redissonProperties.getTransportMode());
|
||||
|
||||
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
|
||||
// 使用单机模式
|
||||
config.useSingleServer()
|
||||
.setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
|
||||
.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
|
||||
.setDatabase(redisProperties.getDatabase())
|
||||
.setPassword(StrUtil.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
|
||||
.setTimeout(singleServerConfig.getTimeout())
|
||||
.setRetryAttempts(singleServerConfig.getRetryAttempts())
|
||||
.setRetryInterval(singleServerConfig.getRetryInterval())
|
||||
.setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection())
|
||||
.setClientName(singleServerConfig.getClientName())
|
||||
.setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
|
||||
.setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize())
|
||||
.setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
|
||||
.setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
|
||||
.setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
|
||||
.setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval());
|
||||
RedissonClient redissonClient = Redisson.create(config);
|
||||
log.info("初始化 redis 配置");
|
||||
return redissonClient;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultRedisScript<Long> limitScript() {
|
||||
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
||||
redisScript.setScriptText(limitScriptText());
|
||||
redisScript.setResultType(Long.class);
|
||||
return redisScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private String limitScriptText() {
|
||||
return StrUtil.builder()
|
||||
.append("local key = KEYS[1]\n")
|
||||
.append("local count = tonumber(ARGV[1])\n")
|
||||
.append("local time = tonumber(ARGV[2])\n")
|
||||
.append("local current = redis.call('get', key);\n")
|
||||
.append("if current and tonumber(current) > count then\n")
|
||||
.append(" return current;\n")
|
||||
.append("end\n")
|
||||
.append("current = redis.call('incr', key)\n")
|
||||
.append("if tonumber(current) == 1 then\n")
|
||||
.append(" redis.call('expire', key, time)\n")
|
||||
.append("end\n")
|
||||
.append("return current;")
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package com.ruoyi.gateway.config.provider;
|
||||
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 复合的路由存储器
|
||||
*
|
||||
* @author Wenchao Gong
|
||||
* @date 2021-09-11
|
||||
*/
|
||||
public class ComplexRouteDefinitionRepository implements RouteDefinitionRepository {
|
||||
|
||||
private RouteDefinitionRepository localCache;
|
||||
private RouteDefinitionRepository remoteReps;
|
||||
|
||||
public ComplexRouteDefinitionRepository(RouteDefinitionRepository localCache, RouteDefinitionRepository remoteReps)
|
||||
{
|
||||
this.localCache = localCache;
|
||||
this.remoteReps = remoteReps;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<RouteDefinition> getRouteDefinitions()
|
||||
{
|
||||
final Flux<RouteDefinition> routeDefinitions = localCache.getRouteDefinitions();
|
||||
return routeDefinitions.collectList().flatMapIterable(list -> {
|
||||
if(list.isEmpty()) {
|
||||
final Flux<RouteDefinition> definitions = remoteReps.getRouteDefinitions();
|
||||
definitions.collectList().flatMapIterable(routes -> {
|
||||
if(!routes.isEmpty()) {
|
||||
routes.stream().map(m -> {
|
||||
routes.add(m);
|
||||
return Mono.just(m);
|
||||
}).forEach(m -> {
|
||||
localCache.save(m);
|
||||
});
|
||||
}
|
||||
return routes;
|
||||
}).filter(l -> Objects.nonNull(l)).map(m -> list.add(m)).collectList();
|
||||
}
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(Mono<RouteDefinition> route)
|
||||
{
|
||||
remoteReps.save(route);
|
||||
return localCache.save(route);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> delete(Mono<String> routeId)
|
||||
{
|
||||
remoteReps.delete(routeId);
|
||||
return localCache.delete(routeId);
|
||||
}
|
||||
}
|
||||
@ -1,40 +1,41 @@
|
||||
package com.ruoyi.gateway.config.provider;
|
||||
|
||||
import org.redisson.api.RMap;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Redis 路由仓库
|
||||
*
|
||||
* @author Wenchao Gong
|
||||
* @date 2021-09-11
|
||||
*/
|
||||
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
|
||||
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository
|
||||
{
|
||||
public static final String KEY_ROUTES = "ROUTES::";
|
||||
private final RedisTemplate<String, RouteDefinition> redisTemplate;
|
||||
private final RedissonClient redissonClient;
|
||||
|
||||
public RedisRouteDefinitionRepository(RedisTemplate<String, RouteDefinition> redisTemplate)
|
||||
public RedisRouteDefinitionRepository(RedissonClient redissonClient)
|
||||
{
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.redissonClient = redissonClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<RouteDefinition> getRouteDefinitions()
|
||||
{
|
||||
List<RouteDefinition> values = redisTemplate.<String,RouteDefinition>opsForHash().values(KEY_ROUTES);
|
||||
return Flux.fromIterable(values);
|
||||
RMap<String, RouteDefinition> map = redissonClient.getMap(KEY_ROUTES);
|
||||
return Flux.fromIterable(map.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(Mono<RouteDefinition> route)
|
||||
{
|
||||
return route.flatMap(definition -> {
|
||||
redisTemplate.opsForHash().put(KEY_ROUTES, definition.getId(), definition);
|
||||
RMap<String, RouteDefinition> map = redissonClient.getMap(KEY_ROUTES);
|
||||
map.put(definition.getId(), definition);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
@ -43,7 +44,8 @@ public class RedisRouteDefinitionRepository implements RouteDefinitionRepository
|
||||
public Mono<Void> delete(Mono<String> routeId)
|
||||
{
|
||||
return routeId.flatMap(id -> {
|
||||
redisTemplate.opsForHash().delete(KEY_ROUTES, id);
|
||||
RMap<String, RouteDefinition> map = redissonClient.getMap(KEY_ROUTES);
|
||||
map.remove(id);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
@ -0,0 +1,134 @@
|
||||
package com.ruoyi.gateway.config.provider;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.redisson.config.TransportMode;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Redisson 配置属性
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "redisson")
|
||||
public class RedissonProperties
|
||||
{
|
||||
|
||||
/**
|
||||
* 线程池数量,默认值 = 当前处理核数量 * 2
|
||||
*/
|
||||
private int threads;
|
||||
|
||||
/**
|
||||
* Netty线程池数量,默认值 = 当前处理核数量 * 2
|
||||
*/
|
||||
private int nettyThreads;
|
||||
|
||||
/**
|
||||
* 传输模式
|
||||
*/
|
||||
private TransportMode transportMode;
|
||||
|
||||
/**
|
||||
* 单机服务配置
|
||||
*/
|
||||
private SingleServerConfig singleServerConfig;
|
||||
|
||||
/**
|
||||
* 缓存组
|
||||
*/
|
||||
private List<CacheGroup> cacheGroup;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class SingleServerConfig {
|
||||
|
||||
/**
|
||||
* 客户端名称
|
||||
*/
|
||||
private String clientName;
|
||||
|
||||
/**
|
||||
* 最小空闲连接数
|
||||
*/
|
||||
private int connectionMinimumIdleSize;
|
||||
|
||||
/**
|
||||
* 连接池大小
|
||||
*/
|
||||
private int connectionPoolSize;
|
||||
|
||||
/**
|
||||
* 连接空闲超时,单位:毫秒
|
||||
*/
|
||||
private int idleConnectionTimeout;
|
||||
|
||||
/**
|
||||
* 命令等待超时,单位:毫秒
|
||||
*/
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
|
||||
*/
|
||||
private int retryAttempts;
|
||||
|
||||
/**
|
||||
* 命令重试发送时间间隔,单位:毫秒
|
||||
*/
|
||||
private int retryInterval;
|
||||
|
||||
/**
|
||||
* 发布和订阅连接的最小空闲连接数
|
||||
*/
|
||||
private int subscriptionConnectionMinimumIdleSize;
|
||||
|
||||
/**
|
||||
* 发布和订阅连接池大小
|
||||
*/
|
||||
private int subscriptionConnectionPoolSize;
|
||||
|
||||
/**
|
||||
* 单个连接最大订阅数量
|
||||
*/
|
||||
private int subscriptionsPerConnection;
|
||||
|
||||
/**
|
||||
* DNS监测时间间隔,单位:毫秒
|
||||
*/
|
||||
private int dnsMonitoringInterval;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class CacheGroup {
|
||||
|
||||
/**
|
||||
* 组id
|
||||
*/
|
||||
private String groupId;
|
||||
|
||||
/**
|
||||
* 组过期时间
|
||||
*/
|
||||
private long ttl;
|
||||
|
||||
/**
|
||||
* 组最大空闲时间
|
||||
*/
|
||||
private long maxIdleTime;
|
||||
|
||||
/**
|
||||
* 组最大长度
|
||||
*/
|
||||
private int maxSize;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -29,6 +29,38 @@ spring:
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# 线程池数量
|
||||
threads: 16
|
||||
# Netty线程池数量
|
||||
nettyThreads: 32
|
||||
# 传输模式
|
||||
transportMode: "NIO"
|
||||
# 单节点配置
|
||||
singleServerConfig:
|
||||
# 客户端名称
|
||||
clientName: ${ruoyi.name}
|
||||
# 最小空闲连接数
|
||||
connectionMinimumIdleSize: 32
|
||||
# 连接池大小
|
||||
connectionPoolSize: 64
|
||||
# 连接空闲超时,单位:毫秒
|
||||
idleConnectionTimeout: 10000
|
||||
# 命令等待超时,单位:毫秒
|
||||
timeout: 3000
|
||||
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
|
||||
retryAttempts: 3
|
||||
# 命令重试发送时间间隔,单位:毫秒
|
||||
retryInterval: 1500
|
||||
# 发布和订阅连接的最小空闲连接数
|
||||
subscriptionConnectionMinimumIdleSize: 1
|
||||
# 发布和订阅连接池大小
|
||||
subscriptionConnectionPoolSize: 50
|
||||
# 单个连接最大订阅数量
|
||||
subscriptionsPerConnection: 5
|
||||
# DNS监测时间间隔,单位:毫秒
|
||||
dnsMonitoringInterval: 5000
|
||||
|
||||
--- # Actuator 监控端点的配置项
|
||||
management:
|
||||
endpoints:
|
||||
@ -41,4 +73,4 @@ management:
|
||||
include: @endpoints.include@
|
||||
endpoint:
|
||||
logfile:
|
||||
external-file: ./logs/sys-console.log
|
||||
external-file: ./logs/sys-console.log
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
--- # 监控配置
|
||||
spring:
|
||||
boot:
|
||||
admin:
|
||||
# Spring Boot Admin Client 客户端的相关配置
|
||||
client:
|
||||
# 增加客户端开关
|
||||
enabled: true
|
||||
# 设置 Spring Boot Admin Server 地址
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
prefer-ip: true # 注册实例时,优先使用 IP
|
||||
username: ruoyi
|
||||
password: 123456
|
||||
|
||||
--- # redis 配置
|
||||
spring:
|
||||
redis:
|
||||
# 地址
|
||||
host: 127.0.0.1
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
# 是否开启ssl
|
||||
ssl: false
|
||||
|
||||
redisson:
|
||||
# 线程池数量
|
||||
threads: 16
|
||||
# Netty线程池数量
|
||||
nettyThreads: 32
|
||||
# 传输模式
|
||||
transportMode: "NIO"
|
||||
# 单节点配置
|
||||
singleServerConfig:
|
||||
# 客户端名称
|
||||
clientName: ${ruoyi.name}
|
||||
# 最小空闲连接数
|
||||
connectionMinimumIdleSize: 32
|
||||
# 连接池大小
|
||||
connectionPoolSize: 64
|
||||
# 连接空闲超时,单位:毫秒
|
||||
idleConnectionTimeout: 10000
|
||||
# 命令等待超时,单位:毫秒
|
||||
timeout: 3000
|
||||
# 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。
|
||||
retryAttempts: 3
|
||||
# 命令重试发送时间间隔,单位:毫秒
|
||||
retryInterval: 1500
|
||||
# 发布和订阅连接的最小空闲连接数
|
||||
subscriptionConnectionMinimumIdleSize: 1
|
||||
# 发布和订阅连接池大小
|
||||
subscriptionConnectionPoolSize: 50
|
||||
# 单个连接最大订阅数量
|
||||
subscriptionsPerConnection: 5
|
||||
# DNS监测时间间隔,单位:毫秒
|
||||
dnsMonitoringInterval: 5000
|
||||
|
||||
--- # Actuator 监控端点的配置项
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
# Actuator 提供的 API 接口的根目录。默认为 /actuator
|
||||
base-path: /actuator
|
||||
exposure:
|
||||
# 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
|
||||
# 生产环境不建议放开所有 根据项目需求放开即可
|
||||
include: @endpoints.include@
|
||||
endpoint:
|
||||
logfile:
|
||||
external-file: ./logs/sys-console.log
|
||||
@ -1,3 +1,15 @@
|
||||
# 项目相关配置
|
||||
ruoyi:
|
||||
# 名称
|
||||
name: RuoYi-Vue-Plus
|
||||
# 版本
|
||||
version: ${ruoyi-vue-plus.version}
|
||||
# 版权年份
|
||||
copyrightYear: 2021
|
||||
# 实例演示开关
|
||||
demoEnabled: true
|
||||
# 获取ip地址开关
|
||||
addressEnabled: true
|
||||
server:
|
||||
port: 8090
|
||||
# Spring配置
|
||||
|
||||
Loading…
Reference in New Issue
Block a user