Redis多database(数据源)

Redis哨兵模式切换database

为了实现数据隔离
本文是切换redis的database
用同样的方法也可以切换不同的redis服务器或者集群

注册多个RedisTemplate

实现了BeanFactoryAware接口,会在Bean初始化阶段执行其方法
多个Redis实例也可使用这种方式

get(String topOrg) 方法可以根据topOrg去BeanFactory中获取对应的redisTemplate
topOrg可以存在ThreadLocal或者其他地方

@Component
public class RedisUtilFactory implements BeanFactoryAware {

    private final static Logger logger = LoggerFactory.getLogger(RedisUtilFactory.class);

    @Autowired
    private RedisUtilConfig redisUtilConfig;

    private static DefaultListableBeanFactory beanFactory;


    /**
     * get current redisTemplate
     *
     * @return
     */
    public RedisTemplate get(String topOrg) {
        String beanName = composeBeanName(topOrg);
        if (beanFactory.containsBean(beanName)) {
            Object bean = beanFactory.getBean(beanName);
            if (bean instanceof RedisTemplate) {
                return (RedisTemplate) bean;
            }
        }
        // todo exception
        logger.info("can not find redisTemplate by topOrg");
        return null;
    }

    /**
     * get current redisTemplate
     *
     * @return
     */
    public RedisTemplate get() {
        return get(ContextUtil.getTopOrg());
    }


    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) beanFactory;


        logger.info("[databaseMap]" + redisUtilConfig.getDatabase().toString());

        for (String topOrg : redisUtilConfig.getDatabase().keySet()) {
            String beanName = composeBeanName(topOrg);
            if (!listableBeanFactory.containsBean(beanName)) {
                listableBeanFactory.registerSingleton(beanName, redisUtilConfig.getRedisTemplate(redisUtilConfig.getDatabase().get(topOrg)));
            }
        }
        RedisUtilFactory.beanFactory = listableBeanFactory;
    }

    private String composeBeanName(String topOrg) {
        return RedisTemplate.class.getSimpleName() + redisUtilConfig.getDatabase().get(topOrg);
    }

}

redis配置类

package com.oneconnect.sg.config;

import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@EnableConfigurationProperties(RedisConfigProperties.class)
@Component
public class RedisConfigUtil {
    private RedisConfigProperties redisConfigProperties;

    @Autowired
    JedisPoolConfig jedisPoolConfig;

    RedisConfigUtil(RedisConfigProperties redisConfigProperties) {
        this.redisConfigProperties = redisConfigProperties;
    }

    public RedisTemplate<String, Object> getRedisTemplate(int database) {
        JedisClientConfiguration.JedisClientConfigurationBuilder clientConfigurationBuilder = JedisClientConfiguration.builder();
        clientConfigurationBuilder.connectTimeout(Duration.ofMillis(redisConfigProperties.getTimeout()));

        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder poolingClientConfigurationBuilder = clientConfigurationBuilder.usePooling();
        poolingClientConfigurationBuilder.poolConfig(jedisPoolConfig);

        JedisConnectionFactory jedisConnectionFactory;
        if (ObjectUtils.isEmpty(redisConfigProperties.getSentinel()) || !redisConfigProperties.getSentinel().isEnabled()) {
            // 单机redis初始化
            jedisConnectionFactory = initJedisConnectionFactory(database, clientConfigurationBuilder);
        } else {
            // 哨兵redis初始化
            jedisConnectionFactory = initJedisConnectFactoryWithSentinels(database, clientConfigurationBuilder);
        }

        // 实例化 RedisTemplate 对象
        RedisTemplate<String, Object> redisTemplate = functionDomainRedisTemplate(jedisConnectionFactory);

        // 不是spring自动初始化的jedisConnectionFactory和redisTemplate需要执行该方法
        jedisConnectionFactory.afterPropertiesSet();
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * 单机版redis初始化
     *
     * @param clientConfigurationBuilder
     * @return
     * @Param database
     */
    private JedisConnectionFactory initJedisConnectionFactory(int database, JedisClientConfiguration.JedisClientConfigurationBuilder clientConfigurationBuilder) {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisConfigProperties.getHost());
        redisStandaloneConfiguration.setPort(redisConfigProperties.getPort());
        redisStandaloneConfiguration.setPassword(redisConfigProperties.getPassword());
        redisStandaloneConfiguration.setDatabase(database);
        return new JedisConnectionFactory(redisStandaloneConfiguration, clientConfigurationBuilder.build());
    }

    /**
     * 哨兵版redis初始化
     *
     * @param clientConfigurationBuilder
     * @return
     * @Param database
     */
    private JedisConnectionFactory initJedisConnectFactoryWithSentinels(int database, JedisClientConfiguration.JedisClientConfigurationBuilder clientConfigurationBuilder) {
        RedisSentinelConfiguration sentinelConfiguration = new RedisSentinelConfiguration();
        sentinelConfiguration.setPassword(redisConfigProperties.getPassword());
        sentinelConfiguration.setDatabase(database);

        RedisNode master = new RedisNode(redisConfigProperties.getHost(), redisConfigProperties.getPort());
        master.setName(redisConfigProperties.getSentinel().getMaster().getName());
        sentinelConfiguration.setMaster(master);

        List<RedisNode> redisNodes = new ArrayList<>();
        List<String> nodes = Arrays.asList(redisConfigProperties.getSentinel().getSentinels().split(";"));
        nodes.forEach(s ->
                redisNodes.add(new RedisNode(s.split(":")[0], NumberUtils.toInt(s.split(":")[1])))
        );
        sentinelConfiguration.setSentinels(redisNodes);

        return new JedisConnectionFactory(sentinelConfiguration, clientConfigurationBuilder.build());
    }

    /**
     * 实例化 RedisTemplate 对象
     *
     * @return RedisTemplate
     */
    private RedisTemplate<String, Object> functionDomainRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        // 开启事务
        redisTemplate.setEnableTransactionSupport(false);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}

ConfigurationProperties

package com.oneconnect.sg.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.HashMap;
import java.util.Map;

@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfigProperties {

    private String host;

    private Integer port;

    private String password;

    private Integer timeout;

    private Integer maxIdle;

    private Integer maxTotal;

    private Integer maxWaitMillis;

    private Integer minEvictableIdleTimeMillis;

    private Integer numTestsPerEvictionRun;

    private long timeBetweenEvictionRunsMillis;

    private boolean testOnBorrow;

    private boolean testWhileIdle;

    private Sentinel sentinel;

    private Map<String, Integer> database = new HashMap<>();

    public String getHost() {
        return host;
    }

    public void setHost(String hostName) {
        this.host = hostName;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getTimeout() {
        return timeout;
    }

    public void setTimeout(Integer timeout) {
        this.timeout = timeout;
    }

    public Integer getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(Integer maxIdle) {
        this.maxIdle = maxIdle;
    }

    public Integer getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(Integer maxTotal) {
        this.maxTotal = maxTotal;
    }

    public Integer getMaxWaitMillis() {
        return maxWaitMillis;
    }

    public void setMaxWaitMillis(Integer maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }

    public Integer getMinEvictableIdleTimeMillis() {
        return minEvictableIdleTimeMillis;
    }

    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    public Integer getNumTestsPerEvictionRun() {
        return numTestsPerEvictionRun;
    }

    public void setNumTestsPerEvictionRun(Integer numTestsPerEvictionRun) {
        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
    }

    public long getTimeBetweenEvictionRunsMillis() {
        return timeBetweenEvictionRunsMillis;
    }

    public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    public boolean isTestOnBorrow() {
        return testOnBorrow;
    }

    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    public boolean isTestWhileIdle() {
        return testWhileIdle;
    }

    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }

    public Sentinel getSentinel() {
        return sentinel;
    }

    public void setSentinel(Sentinel sentinel) {
        this.sentinel = sentinel;
    }

    public Map<String, Integer> getDatabase() {
        return database;
    }

    public void setDatabase(Map<String, Integer> database) {
        this.database = database;
    }

    /**
     * Redis sentinel properties.
     */
    public static class Sentinel {

        private boolean enabled;

        /**
         * Name of the Redis server.
         */
        private Master master;

        /**
         * Comma-separated list of "host:port" pairs.
         */
        private String sentinels;

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }

        public Master getMaster() {
            return master;
        }

        public void setMaster(Master master) {
            this.master = master;
        }

        public String getSentinels() {
            return sentinels;
        }

        public void setSentinels(String sentinels) {
            this.sentinels = sentinels;
        }
    }

    public static class Master {
        /**
         * Name of the Redis server.
         */
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

连接池

package com.oneconnect.sg.config;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ObjectUtils;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


@Configuration
@EnableConfigurationProperties(RedisConfigProperties.class)
public class RedisPoolConfig {

    private RedisConfigProperties redisConfigProperties;

    RedisPoolConfig(RedisConfigProperties redisConfigProperties) {
        this.redisConfigProperties = redisConfigProperties;
    }

    /**
     * JedisPoolConfig 连接池
     *
     * @return JedisPoolConfig
     */
    @Bean
    protected JedisPoolConfig jedisPoolConfig() {
        if (StringUtils.isEmpty(redisConfigProperties.getHost()) || ObjectUtils.isEmpty(redisConfigProperties.getDatabase())) {
            return new JedisPoolConfig();
        }
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大空闲数
        jedisPoolConfig.setMaxIdle(redisConfigProperties.getMaxIdle());
        // 连接池的最大数据库连接数
        jedisPoolConfig.setMaxTotal(redisConfigProperties.getMaxTotal());
        // 最大建立连接等待时间
        jedisPoolConfig.setMaxWaitMillis(redisConfigProperties.getMaxWaitMillis());
        // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        jedisPoolConfig.setMinEvictableIdleTimeMillis(redisConfigProperties.getMinEvictableIdleTimeMillis());
        // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        jedisPoolConfig.setNumTestsPerEvictionRun(redisConfigProperties.getNumTestsPerEvictionRun());
        // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(redisConfigProperties.getTimeBetweenEvictionRunsMillis());
        // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        jedisPoolConfig.setTestOnBorrow(redisConfigProperties.isTestOnBorrow());
        // 在空闲时检查有效性, 默认false
        jedisPoolConfig.setTestWhileIdle(redisConfigProperties.isTestWhileIdle());
        return jedisPoolConfig;
    }


}

配置文件

spring:
  redis:
    host: x.x.x.x
    #使用的数据库
    database:
      topOrg1: 0
      topOrg2: 1
      topOrg3: 2
    #端口号
    port: 16379
    #如果有密码
    password:
    #客户端超时时间单位是毫秒 默认是2000
    timeout: 10000
    #最大空闲数
    maxIdle: 300
    #连接池的最大数据库连接数。设为0表示无限制,如果是jedis 2.4以后用redis.maxTotal
    #maxActive: 600
    #控制一个pool可分配多少个jedis实例,用来替换上面的redis.maxActive,如果是jedis 2.4以后用该属性
    maxTotal: 300
    #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
    maxWaitMillis: 1000
    #连接的最小空闲时间 默认1800000毫秒(30分钟)
    minEvictableIdleTimeMillis: 300000
    #每次释放连接的最大数目,默认3
    numTestsPerEvictionRun: 1024
    #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
    timeBetweenEvictionRunsMillis: 30000
    #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
    testOnBorrow: true
    #在空闲时检查有效性, 默认false
    testWhileIdle: true
    sentinel:
      enabled: true
      master:
        name: pubredis
      sentinels: x.x.x.x:16379;x.x.x.x:16379

发布了37 篇原创文章 · 获赞 1 · 访问量 1041

猜你喜欢

转载自blog.csdn.net/zhuchencn/article/details/104664286
今日推荐