首先我们要导入sentinel的坐标,官方提供
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-redis</artifactId>
<version>1.7.0</version>
</dependency>
这就我们我们主要的配置了,接下来我们来说
属性lcal,redisSentinelPort,passWord就不多说了,是读取我们的redis配置
设置@PostConstruct来设置项目启动就加载
关于rulekey和channel,就是redis数据的key
还有两个模板类RedisConnectionConfig,RedisDataSource,我放在下面了
@Component
public class CreateConnection {
private final String ruleKey = "sentinel.rules.flow.ruleKey";
private final String channel = "sentinel.rules.flow.channel";
private final int database = 0;
protected Log log = LogFactory.getLog(this.getClass());
@Value("${spring.redis.host}")
private String lcal;
@Value("${spring.redis.port}")
private int redisSentinelPort;
@Value("${spring.redis.password}")
private String passWord;
@PostConstruct
public void initValue() {
//初始化连接对象
RedisConnectionConfig redisConnectionConfig = RedisConnectionConfig.builder().withHost(lcal).withPort(redisSentinelPort).withPassword(passWord).withDatabase(database).build();
www(redisConnectionConfig);
}
/**
* 规则举例 官方模板,可以写死,json对象
* // int maxQueueingTimeMs = new Random().nextInt();
* // String flowRulesJson =
* // "[{\"resource\":\"blindBox\", \"limitApp\":\"default\", \"grade\":1, \"count\":\"10\", \"strategy\":0, "
* // + "\"refResource\":null, "
* // +
* // "\"controlBehavior\":0, \"warmUpPeriodSec\":10, \"maxQueueingTimeMs\":" + maxQueueingTimeMs
* // + ", \"controller\":null}]";
* @param redisConnectionConfig
*/
public void www(RedisConnectionConfig redisConnectionConfig) {
Converter<String, List<FlowRule>> flowConfigParser = buildFlowConfigParser();
ReadableDataSource<String, List<FlowRule>> redisDataSource = new RedisDataSource<List<FlowRule>>(redisConnectionConfig, ruleKey, channel, flowConfigParser);
FlowRuleManager.register2Property(redisDataSource.getProperty());
String jsonResult = addResult();
pushRules(jsonResult);
}
/**
* 添加限流规则
* @return
*/
private String addResult() {
FlowRule sentinelDto = new FlowRule();
List<FlowRule> objects = new ArrayList<>();
// 限流名称
sentinelDto.setResource("xxxxx");
sentinelDto.setLimitApp("default");
//阈值类型,0线程数,1QPS
sentinelDto.setGrade(1);
//单机阈值
sentinelDto.setCount(10);
//流控模式,0表示直接,1表示关联,2表示链路
sentinelDto.setStrategy(0);
//流控效果 ,0表示快速失败,1表示warm up,2表示排队等待
sentinelDto.setControlBehavior(0);
//是否集群
sentinelDto.setClusterMode(false);
objects.add(sentinelDto);
String ruleList = JSON.toJSONString(objects);
return ruleList;
}
/**
* 初始化规则
* @return
*/
private Converter<String, List<FlowRule>> buildFlowConfigParser() {
return source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
});
}
/**
* 单机启动 双节点要更换
*
* @param value
* @param <T>
*/
public <T> void pushRules(String value) {
RedisURI build = RedisURI.Builder.redis(lcal, redisSentinelPort).withDatabase(database).withPassword(passWord).build();
RedisClient redisClient1 = RedisClient.create(build);
StatefulRedisPubSubConnection<String, String> connection = redisClient1.connectPubSub();
RedisPubSubCommands<String, String> subCommands = connection.sync();
subCommands.multi();
subCommands.set(ruleKey, value);
subCommands.publish(channel, value);
subCommands.exec();
}
成功启动项目后,redis如图
RedisConnectionConfig,RedisDataSource 因为一些版权原因,就直接以代码形式给大家了
package com.yami.shop.api.config;
import com.alibaba.csp.sentinel.datasource.redis.config.RedisHostAndPort;
import com.alibaba.csp.sentinel.util.AssertUtil;
import jodd.util.StringUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Administrator
* @version 1.0
* @description: TODO
* @date 2022/10/29 14:30
*/
public class RedisConnectionConfig {
/**
* The default redisSentinel port.
*/
public static final int DEFAULT_SENTINEL_PORT = 26379;
/**
* The default redisCluster port.
*/
public static final int DEFAULT_CLUSTER_PORT = 6379;
/**
* The default redis port.
*/
public static final int DEFAULT_REDIS_PORT = 6379;
/**
* Default timeout: 60 sec
*/
public static final long DEFAULT_TIMEOUT_MILLISECONDS = 60 * 1000;
private final List<RedisConnectionConfig> redisSentinels = new ArrayList<RedisConnectionConfig>();
private final List<RedisConnectionConfig> redisClusters = new ArrayList<RedisConnectionConfig>();
private String host;
private String redisSentinelMasterId;
private int port;
private int database = 1;
private String clientName;
private char[] password;
private long timeout = DEFAULT_TIMEOUT_MILLISECONDS;
/**
* Default empty constructor.
*/
public RedisConnectionConfig() {
}
/**
* Constructor with host/port and timeout.
*
* @param host the host
* @param port the port
* @param timeout timeout value . unit is mill seconds
*/
public RedisConnectionConfig(String host, int port, long timeout) {
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.notNull(timeout, "Timeout duration must not be null");
AssertUtil.isTrue(timeout >= 0, "Timeout duration must be greater or equal to zero");
setHost(host);
setPort(port);
setTimeout(timeout);
}
/**
* Returns a new {@link RedisConnectionConfig.Builder} to construct a {@link RedisConnectionConfig}.
*
* @return a new {@link RedisConnectionConfig.Builder} to construct a {@link RedisConnectionConfig}.
*/
public static RedisConnectionConfig.Builder builder() {
return new RedisConnectionConfig.Builder();
}
/**
* Return true for valid port numbers.
*/
private static boolean isValidPort(int port) {
return port >= 0 && port <= 65535;
}
/**
* Returns the host.
*
* @return the host.
*/
public String getHost() {
return host;
}
/**
* Sets the Redis host.
*
* @param host the host
*/
public void setHost(String host) {
this.host = host;
}
/**
* Returns the Sentinel Master Id.
*
* @return the Sentinel Master Id.
*/
public String getRedisSentinelMasterId() {
return redisSentinelMasterId;
}
/**
* Sets the Sentinel Master Id.
*
* @param redisSentinelMasterId the Sentinel Master Id.
*/
public void setRedisSentinelMasterId(String redisSentinelMasterId) {
this.redisSentinelMasterId = redisSentinelMasterId;
}
/**
* Returns the Redis port.
*
* @return the Redis port
*/
public int getPort() {
return port;
}
/**
* Sets the Redis port. Defaults to {@link #DEFAULT_REDIS_PORT}.
*
* @param port the Redis port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Returns the password.
*
* @return the password
*/
public char[] getPassword() {
return password;
}
/**
* Sets the password. Use empty string to skip authentication.
*
* @param password the password, must not be {@literal null}.
*/
public void setPassword(String password) {
AssertUtil.notNull(password, "Password must not be null");
this.password = password.toCharArray();
}
/**
* Sets the password. Use empty char array to skip authentication.
*
* @param password the password, must not be {@literal null}.
*/
public void setPassword(char[] password) {
AssertUtil.notNull(password, "Password must not be null");
this.password = Arrays.copyOf(password, password.length);
}
/**
* Returns the command timeout for synchronous command execution.
*
* @return the Timeout
*/
public long getTimeout() {
return timeout;
}
/**
* Sets the command timeout for synchronous command execution.
*
* @param timeout the command timeout for synchronous command execution.
*/
public void setTimeout(Long timeout) {
AssertUtil.notNull(timeout, "Timeout must not be null");
AssertUtil.isTrue(timeout >= 0, "Timeout must be greater or equal 0");
this.timeout = timeout;
}
/**
* Returns the Redis database number. Databases are only available for Redis Standalone and Redis Master/Slave.
*
* @return database
*/
public int getDatabase() {
return database;
}
/**
* Sets the Redis database number. Databases are only available for Redis Standalone and Redis Master/Slave.
*
* @param database the Redis database number.
*/
public void setDatabase(int database) {
AssertUtil.isTrue(database >= 0, "Invalid database number: " + database);
this.database = database;
}
/**
* Returns the client name.
*
* @return
*/
public String getClientName() {
return clientName;
}
/**
* Sets the client name to be applied on Redis connections.
*
* @param clientName the client name.
*/
public void setClientName(String clientName) {
this.clientName = clientName;
}
/**
* @return the list of {@link RedisConnectionConfig Redis Sentinel URIs}.
*/
public List<RedisConnectionConfig> getRedisSentinels() {
return redisSentinels;
}
/**
* @return the list of {@link RedisConnectionConfig Redis Cluster URIs}.
*/
public List<RedisConnectionConfig> getRedisClusters() {
return redisClusters;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
if (host != null) {
sb.append("host='").append(host).append('\'');
sb.append(", port=").append(port);
}
if (redisSentinelMasterId != null) {
sb.append("redisSentinels=").append(getRedisSentinels());
sb.append(", redisSentinelMasterId=").append(redisSentinelMasterId);
}
if (redisClusters.size() > 0) {
sb.append("redisClusters=").append(getRedisClusters());
}
sb.append(']');
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RedisConnectionConfig)) {
return false;
}
RedisConnectionConfig redisURI = (RedisConnectionConfig) o;
if (port != redisURI.port) {
return false;
}
if (database != redisURI.database) {
return false;
}
if (host != null ? !host.equals(redisURI.host) : redisURI.host != null) {
return false;
}
if (redisSentinelMasterId != null ? !redisSentinelMasterId.equals(redisURI.redisSentinelMasterId)
: redisURI.redisSentinelMasterId != null) {
return false;
}
if (redisClusters != null ? !redisClusters.equals(redisURI.redisClusters)
: redisURI.redisClusters != null) {
return false;
}
return !(redisSentinels != null ? !redisSentinels.equals(redisURI.redisSentinels)
: redisURI.redisSentinels != null);
}
@Override
public int hashCode() {
int result = host != null ? host.hashCode() : 0;
result = 31 * result + (redisSentinelMasterId != null ? redisSentinelMasterId.hashCode() : 0);
result = 31 * result + port;
result = 31 * result + database;
result = 31 * result + (redisSentinels != null ? redisSentinels.hashCode() : 0);
result = 31 * result + (redisClusters != null ? redisClusters.hashCode() : 0);
return result;
}
/**
* Builder for Redis RedisConnectionConfig.
*/
public static class Builder {
private final List<RedisHostAndPort> redisSentinels = new ArrayList<RedisHostAndPort>();
private final List<RedisHostAndPort> redisClusters = new ArrayList<RedisHostAndPort>();
private String host;
private String redisSentinelMasterId;
private int port;
private int database;
private String clientName;
private char[] password;
private long timeout = DEFAULT_TIMEOUT_MILLISECONDS;
private Builder() {
}
/**
* Set Redis host. Creates a new builder.
*
* @param host the host name
* @return New builder with Redis host/port.
*/
public static RedisConnectionConfig.Builder redis(String host) {
return redis(host, DEFAULT_REDIS_PORT);
}
/**
* Set Redis host and port. Creates a new builder
*
* @param host the host name
* @param port the port
* @return New builder with Redis host/port.
*/
public static RedisConnectionConfig.Builder redis(String host, int port) {
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
Builder builder = RedisConnectionConfig.builder();
return builder.withHost(host).withPort(port);
}
/**
* Set Sentinel host. Creates a new builder.
*
* @param host the host name
* @return New builder with Sentinel host/port.
*/
public static RedisConnectionConfig.Builder redisSentinel(String host) {
AssertUtil.notEmpty(host, "Host must not be empty");
RedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();
return builder.withRedisSentinel(host);
}
/**
* Set Sentinel host and port. Creates a new builder.
*
* @param host the host name
* @param port the port
* @return New builder with Sentinel host/port.
*/
public static RedisConnectionConfig.Builder redisSentinel(String host, int port) {
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
RedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();
return builder.withRedisSentinel(host, port);
}
/**
* Set Sentinel host and master id. Creates a new builder.
*
* @param host the host name
* @param masterId redisSentinel master id
* @return New builder with Sentinel host/port.
*/
public static RedisConnectionConfig.Builder redisSentinel(String host, String masterId) {
return redisSentinel(host, DEFAULT_SENTINEL_PORT, masterId);
}
/**
* Set Sentinel host, port and master id. Creates a new builder.
*
* @param host the host name
* @param port the port
* @param masterId redisSentinel master id
* @return New builder with Sentinel host/port.
*/
public static RedisConnectionConfig.Builder redisSentinel(String host, int port, String masterId) {
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
RedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();
return builder.withSentinelMasterId(masterId).withRedisSentinel(host, port);
}
/**
* Set Cluster host. Creates a new builder.
*
* @param host the host name
* @return New builder with Cluster host/port.
*/
public static RedisConnectionConfig.Builder redisCluster(String host) {
AssertUtil.notEmpty(host, "Host must not be empty");
RedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();
return builder.withRedisCluster(host);
}
/**
* Set Cluster host and port. Creates a new builder.
*
* @param host the host name
* @param port the port
* @return New builder with Cluster host/port.
*/
public static RedisConnectionConfig.Builder redisCluster(String host, int port) {
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
RedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();
return builder.withRedisCluster(host, port);
}
/**
* Add a withRedisSentinel host to the existing builder.
*
* @param host the host name
* @return the builder
*/
public RedisConnectionConfig.Builder withRedisSentinel(String host) {
return withRedisSentinel(host, DEFAULT_SENTINEL_PORT);
}
/**
* Add a withRedisSentinel host/port to the existing builder.
*
* @param host the host name
* @param port the port
* @return the builder
*/
public RedisConnectionConfig.Builder withRedisSentinel(String host, int port) {
AssertUtil.assertState(this.host == null, "Cannot use with Redis mode.");
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
redisSentinels.add(RedisHostAndPort.of(host, port));
return this;
}
/**
* Add a withRedisCluster host to the existing builder.
*
* @param host the host name
* @return the builder
*/
public RedisConnectionConfig.Builder withRedisCluster(String host) {
return withRedisCluster(host, DEFAULT_CLUSTER_PORT);
}
/**
* Add a withRedisCluster host/port to the existing builder.
*
* @param host the host name
* @param port the port
* @return the builder
*/
public RedisConnectionConfig.Builder withRedisCluster(String host, int port) {
AssertUtil.assertState(this.host == null, "Cannot use with Redis mode.");
AssertUtil.notEmpty(host, "Host must not be empty");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
redisClusters.add(RedisHostAndPort.of(host, port));
return this;
}
/**
* Adds host information to the builder. Does only affect Redis URI, cannot be used with Sentinel connections.
*
* @param host the port
* @return the builder
*/
public RedisConnectionConfig.Builder withHost(String host) {
AssertUtil.assertState(this.redisSentinels.isEmpty(),
"Sentinels are non-empty. Cannot use in Sentinel mode.");
AssertUtil.notEmpty(host, "Host must not be empty");
this.host = host;
return this;
}
/**
* Adds port information to the builder. Does only affect Redis URI, cannot be used with Sentinel connections.
*
* @param port the port
* @return the builder
*/
public RedisConnectionConfig.Builder withPort(int port) {
AssertUtil.assertState(this.host != null, "Host is null. Cannot use in Sentinel mode.");
AssertUtil.isTrue(isValidPort(port), String.format("Port out of range: %s", port));
this.port = port;
return this;
}
/**
* Configures the database number.
*
* @param database the database number
* @return the builder
*/
public RedisConnectionConfig.Builder withDatabase(int database) {
AssertUtil.isTrue(database >= 0, "Invalid database number: " + database);
this.database = database;
return this;
}
/**
* Configures a client name.
*
* @param clientName the client name
* @return the builder
*/
public RedisConnectionConfig.Builder withClientName(String clientName) {
AssertUtil.notNull(clientName, "Client name must not be null");
this.clientName = clientName;
return this;
}
/**
* Configures authentication.
*
* @param password the password
* @return the builder
*/
public RedisConnectionConfig.Builder withPassword(String password) {
AssertUtil.notNull(password, "Password must not be null");
return withPassword(password.toCharArray());
}
/**
* Configures authentication.
*
* @param password the password
* @return the builder
*/
public RedisConnectionConfig.Builder withPassword(char[] password) {
AssertUtil.notNull(password, "Password must not be null");
this.password = Arrays.copyOf(password, password.length);
return this;
}
/**
* Configures a timeout.
*
* @param timeout must not be {@literal null} or negative.
* @return the builder
*/
public RedisConnectionConfig.Builder withTimeout(long timeout) {
AssertUtil.notNull(timeout, "Timeout must not be null");
AssertUtil.notNull(timeout >= 0, "Timeout must be greater or equal 0");
this.timeout = timeout;
return this;
}
/**
* Configures a redisSentinel master Id.
*
* @param sentinelMasterId redisSentinel master id, must not be empty or {@literal null}
* @return the builder
*/
public RedisConnectionConfig.Builder withSentinelMasterId(String sentinelMasterId) {
AssertUtil.notEmpty(sentinelMasterId, "Sentinel master id must not empty");
this.redisSentinelMasterId = sentinelMasterId;
return this;
}
/**
* @return the RedisConnectionConfig.
*/
public RedisConnectionConfig build() {
if (redisSentinels.isEmpty() && redisClusters.isEmpty() && StringUtil.isEmpty(host)) {
throw new IllegalStateException(
"Cannot build a RedisConnectionConfig. One of the following must be provided Host, Socket, Cluster or "
+ "Sentinel");
}
RedisConnectionConfig redisURI = new RedisConnectionConfig();
redisURI.setHost(host);
redisURI.setPort(port);
if (password != null) {
redisURI.setPassword(password);
}
redisURI.setDatabase(database);
redisURI.setClientName(clientName);
redisURI.setRedisSentinelMasterId(redisSentinelMasterId);
for (RedisHostAndPort sentinel : redisSentinels) {
redisURI.getRedisSentinels().add(
new RedisConnectionConfig(sentinel.getHost(), sentinel.getPort(), timeout));
}
for (RedisHostAndPort sentinel : redisClusters) {
redisURI.getRedisClusters().add(
new RedisConnectionConfig(sentinel.getHost(), sentinel.getPort(), timeout));
}
redisURI.setTimeout(timeout);
return redisURI;
}
}
}
package com.yami.shop.api.config;
/**
* @author Administrator
* @version 1.0
* @description: TODO
* @date 2022/10/29 14:28
*/
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.StringUtil;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
import io.lettuce.core.cluster.pubsub.StatefulRedisClusterPubSubConnection;
import io.lettuce.core.pubsub.RedisPubSubAdapter;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.pubsub.api.sync.RedisPubSubCommands;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* <p>
* A read-only {@code DataSource} with Redis backend.
* </p>
* <p>
* The data source first loads initial rules from a Redis String during initialization.
* Then the data source subscribe from specific channel. When new rules is published to the channel,
* the data source will observe the change in realtime and update to memory.
* </p>
* <p>
* Note that for consistency, users should publish the value and save the value to the ruleKey simultaneously
* like this (using Redis transaction):
* <pre>
* MULTI
* SET ruleKey value
* PUBLISH channel value
* EXEC
* </pre>
* </p>
*
* @author tiger
*/
public class RedisDataSource<T> extends AbstractDataSource<String, T> {
private final RedisClient redisClient;
private final RedisClusterClient redisClusterClient;
private final String ruleKey;
/**
* Constructor of {@code RedisDataSource}.
*
* @param connectionConfig Redis connection config
* @param ruleKey data key in Redis
* @param channel channel to subscribe in Redis
* @param parser customized data parser, cannot be empty
*/
public RedisDataSource(RedisConnectionConfig connectionConfig, String ruleKey, String channel,
Converter<String, T> parser) {
super(parser);
AssertUtil.notNull(connectionConfig, "Redis connection config can not be null");
AssertUtil.notEmpty(ruleKey, "Redis ruleKey can not be empty");
AssertUtil.notEmpty(channel, "Redis subscribe channel can not be empty");
if (connectionConfig.getRedisClusters().size() == 0) {
this.redisClient = getRedisClient(connectionConfig);
this.redisClusterClient = null;
} else {
this.redisClusterClient = getRedisClusterClient(connectionConfig);
this.redisClient = null;
}
this.ruleKey = ruleKey;
loadInitialConfig();
subscribeFromChannel(channel);
}
/**
* Build Redis client fromm {@code RedisConnectionConfig}.
*
* @return a new {@link RedisClient}
*/
private RedisClient getRedisClient(RedisConnectionConfig connectionConfig) {
if (connectionConfig.getRedisSentinels().size() == 0) {
RecordLog.info("[RedisDataSource] Creating stand-alone mode Redis client");
return getRedisStandaloneClient(connectionConfig);
} else {
RecordLog.info("[RedisDataSource] Creating Redis Sentinel mode Redis client");
return getRedisSentinelClient(connectionConfig);
}
}
private RedisClusterClient getRedisClusterClient(RedisConnectionConfig connectionConfig) {
char[] password = connectionConfig.getPassword();
String clientName = connectionConfig.getClientName();
//If any uri is successful for connection, the others are not tried anymore
List<RedisURI> redisUris = new ArrayList<>();
for (RedisConnectionConfig config : connectionConfig.getRedisClusters()) {
RedisURI.Builder clusterRedisUriBuilder = RedisURI.builder();
clusterRedisUriBuilder.withHost(config.getHost())
.withPort(config.getPort())
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
//All redis nodes must have same password
if (password != null) {
clusterRedisUriBuilder.withPassword(connectionConfig.getPassword());
}
redisUris.add(clusterRedisUriBuilder.build());
}
return RedisClusterClient.create(redisUris);
}
private RedisClient getRedisStandaloneClient(RedisConnectionConfig connectionConfig) {
char[] password = connectionConfig.getPassword();
String clientName = connectionConfig.getClientName();
RedisURI.Builder redisUriBuilder = RedisURI.builder();
redisUriBuilder.withHost(connectionConfig.getHost())
.withPort(connectionConfig.getPort())
.withDatabase(connectionConfig.getDatabase())
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
if (password != null) {
redisUriBuilder.withPassword(connectionConfig.getPassword());
}
if (StringUtil.isNotEmpty(connectionConfig.getClientName())) {
redisUriBuilder.withClientName(clientName);
}
return RedisClient.create(redisUriBuilder.build());
}
private RedisClient getRedisSentinelClient(RedisConnectionConfig connectionConfig) {
char[] password = connectionConfig.getPassword();
String clientName = connectionConfig.getClientName();
RedisURI.Builder sentinelRedisUriBuilder = RedisURI.builder();
for (RedisConnectionConfig config : connectionConfig.getRedisSentinels()) {
sentinelRedisUriBuilder.withSentinel(config.getHost(), config.getPort());
}
if (password != null) {
sentinelRedisUriBuilder.withPassword(connectionConfig.getPassword());
}
if (StringUtil.isNotEmpty(connectionConfig.getClientName())) {
sentinelRedisUriBuilder.withClientName(clientName);
}
sentinelRedisUriBuilder.withSentinelMasterId(connectionConfig.getRedisSentinelMasterId())
.withTimeout(Duration.ofMillis(connectionConfig.getTimeout()));
return RedisClient.create(sentinelRedisUriBuilder.build());
}
private void subscribeFromChannel(String channel) {
RedisPubSubAdapter<String, String> adapterListener = new DelegatingRedisPubSubListener();
if (redisClient != null) {
StatefulRedisPubSubConnection<String, String> pubSubConnection = redisClient.connectPubSub();
pubSubConnection.addListener(adapterListener);
RedisPubSubCommands<String, String> sync = pubSubConnection.sync();
sync.subscribe(channel);
} else {
StatefulRedisClusterPubSubConnection<String, String> pubSubConnection = redisClusterClient.connectPubSub();
pubSubConnection.addListener(adapterListener);
RedisPubSubCommands<String, String> sync = pubSubConnection.sync();
sync.subscribe(channel);
}
}
private void loadInitialConfig() {
try {
T newValue = loadConfig();
if (newValue == null) {
RecordLog.warn("[RedisDataSource] WARN: initial config is null, you may have to check your data source");
}
getProperty().updateValue(newValue);
} catch (Exception ex) {
RecordLog.warn("[RedisDataSource] Error when loading initial config", ex);
}
}
@Override
public String readSource() {
if (this.redisClient == null && this.redisClusterClient == null) {
throw new IllegalStateException("Redis client or Redis Cluster client has not been initialized or error occurred");
}
if (redisClient != null) {
RedisCommands<String, String> stringRedisCommands = redisClient.connect().sync();
return stringRedisCommands.get(ruleKey);
} else {
RedisAdvancedClusterCommands<String, String> stringRedisCommands = redisClusterClient.connect().sync();
return stringRedisCommands.get(ruleKey);
}
}
@Override
public void close() {
if (redisClient != null) {
redisClient.shutdown();
} else {
redisClusterClient.shutdown();
}
}
private class DelegatingRedisPubSubListener extends RedisPubSubAdapter<String, String> {
DelegatingRedisPubSubListener() {
}
@Override
public void message(String channel, String message) {
RecordLog.info("[RedisDataSource] New property value received for channel {}: {}", channel, message);
getProperty().updateValue(parser.convert(message));
}
}
}