Sentinel-redis持久化

    首先我们要导入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));
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郎伟学架构

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值