1.前言

本文为大家提供一个 redis 配置多数据源的实现方案;为上一篇文章【Redis 多数据源 Spring Boot 实现】的升级版本

  • 支持自定义配置
  • 无需写任何其他配置 Java 类
  • application.properties 配置完,直接就可以使用

请注意 spring boot 的相关依赖版本。

2.git 示例地址

git 仓库地址:https://github.com/huajiexiewenfeng/redis-multi-spring/tree/dev-1.0

上个版本为 master 分支,本文为 dev-1.0 分支升级版本

3.需求

1.不需要每一个配置都写一个 Properties 类

2.不需要每一个配置都写一个 RedisTemplate 配置

    @Bean("oneRedisTemplate")
    public RedisTemplate<String, Object> oneRedisTemplate() {...}

    @Bean("twoRedisTemplate")
    public RedisTemplate<String, Object> twoRedisTemplate() {...}

3.使用方法可以与 properties 里面的配置直接对应,比如 oneRedisTemplate

    @Autowired
    @Qualifier("oneRedisTemplate")
    private RedisTemplate<String, Object> redisTemplateOne;

对应 application.properties 中的 multi.redis.one 前缀

multi.redis.one.database=${REDIS_DB_INDEX:2}
multi.redis.one.flushdb=${REDIS_FLUSHDB:false}
multi.redis.one.host=${REDIS_HOST:127.0.0.1}
multi.redis.one.port=${REDIS_PORT:6379}
multi.redis.one.password=123456

其中,multi.redis.one 前缀中的 one 为自定义字符串,可以为任意值

比如 multi.redis.csdn.database 对应的 spring bean name 为 csdnRedisTemplate

    @Autowired
    @Qualifier("csdnRedisTemplate")
    private RedisTemplate<String, Object> redisTemplateOne;

4.代码实现

4.1 application.properties 配置文件

配置文件和原版保持一致

spring.application.name=${APPLICATION_NAME:redis-multiple}
server.port=${SERVER_PORT:22216}

# spring 默认配置
spring.redis.database=${REDIS_DB_INDEX:1}
spring.redis.flushdb=${REDIS_FLUSHDB:false}
spring.redis.host=${REDIS_HOST:127.0.0.1}
spring.redis.port=${REDIS_PORT:6379}
spring.redis.password=123456

#第一个 redis 实例配置
multi.redis.one.database=${REDIS_DB_INDEX:2}
multi.redis.one.flushdb=${REDIS_FLUSHDB:false}
multi.redis.one.host=${REDIS_HOST:127.0.0.1}
multi.redis.one.port=${REDIS_PORT:6379}
multi.redis.one.password=123456


#第二个 redis 实例配置
multi.redis.two.database=${REDIS_DB_INDEX:3}
multi.redis.two.flushdb=${REDIS_FLUSHDB:false}
multi.redis.two.host=${REDIS_HOST:127.0.0.1}
multi.redis.two.port=${REDIS_PORT:6379}
multi.redis.two.password=123456

4.2 获取 application.properties 中的 redis 配置

4.2.1 Environment 对象来获取自定义 redis 配置

实现 EnvironmentAware 接口,获取 Environment 对象,从而来获取我们自定义的配置,核心代码如下:

public class RedisMultiConfiguration implements EnvironmentAware, ApplicationContextAware {
    //...此处省略N行代码
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        // 获取 application.properties 对应的 java 类对象
        PropertySource<?> propertySource = ((StandardServletEnvironment) environment).getPropertySources().get("applicationConfig: [classpath:/application.properties]");
        assert propertySource != null;
        Object source = propertySource.getSource();
        // 拿到 redis 配置的前缀集合,例如 multi.redis.xxx...
        Set<String> redisConfigKeys = new HashSet<>();
        if (source instanceof LinkedHashMap) {
            LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) source;
            Set<String> keys = map.keySet();
            for (String key : keys) {
                // find multi.redis properties
                if (key.startsWith("multi.redis")) {
                    redisConfigKeys.add(key.substring(0, StrUtils.findNthOccurrence(key, ".", 3)));
                }
            }
        }
        if (redisConfigKeys.isEmpty()) {
            log.error("redis config not found");
        }
        this.redisConfigKeyPrefixSet = redisConfigKeys;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    //...此处省略N行代码
}

后续再通过 environment.getProperty(keyPrefix + "." + REDIS_CONFIG_HOST_NAME) 就可以拿到参数的值

  • keyPrefix = multi.redis.xxx…

4.3 初始化 RedisTemplate 对象,并注册到 Spring IOC 容器

4.3.1 初始化方法
@Slf4j
@Configuration
public class RedisMultiConfiguration implements EnvironmentAware, ApplicationContextAware {

    private Environment environment;

    private ApplicationContext applicationContext;

    private Set<String> redisConfigKeyPrefixSet = new HashSet<>();

    @PostConstruct
    public void initConfig() {
        if (redisConfigKeyPrefixSet.isEmpty()) {
            return;
        }
        for (String keyPrefix : redisConfigKeyPrefixSet) {
            String key = keyPrefix.replace(MULTI_REDIS_CONFIG_PREFIX, "");
            // 创建自定义 RedisTemplate 对象
            RedisTemplate<String, Object> redisTemplate = CreateRedisTemplate(keyPrefix, environment);
            // 注册到 Spring IOC 容器
            ((AnnotationConfigServletWebServerApplicationContext) applicationContext).getBeanFactory().registerSingleton(key + "RedisTemplate", redisTemplate);
        }
    }
    //...此处省略N行代码
}
4.3.2 CreateRedisTemplate 方法
  private RedisTemplate<String, Object> CreateRedisTemplate(String keyPrefix, Environment environment) {
        JedisConnectionFactory jedisConnectionFactory = this.getJedisConnectionFactory(keyPrefix, environment);
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置key的序列化方式
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        template.setConnectionFactory(jedisConnectionFactory);
        template.setKeySerializer(keySerializer);

        // 设置value的序列化方式
        Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是无论什么都可以序列化
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 启用DefaultTyping,方便我们反序列化时知道对象的类型
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        valueSerializer.setObjectMapper(om);
        template.setValueSerializer(valueSerializer);
        // 设置Hash的key和value序列化方式
        template.setHashKeySerializer(keySerializer);
        template.setHashValueSerializer(valueSerializer);

        // 设置value的泛型类型,这样在存取的时候才会序列化和反序列化成设置的对象类型
        // 注意:这里只是设置了value的泛型,key还是String类型
        template.afterPropertiesSet();
        return template;
    }
4.3.3 getJedisConnectionFactory 方法

通过前缀+ environment 去获取对应的配置,再设置到 JedisConnectionFactory 中。

    private JedisConnectionFactory getJedisConnectionFactory(String keyPrefix, Environment environment) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        // 设置连接池参数,例如最大连接数、最大空闲连接数等
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(30);
        poolConfig.setMinIdle(10);
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.setHostName(StrUtils.ifEmpty(environment.getProperty(keyPrefix + "." + REDIS_CONFIG_HOST_NAME), "127.0.0.1"));
        jedisConnectionFactory.setPort(Integer.parseInt(StrUtils.ifEmpty(environment.getProperty(keyPrefix + "." + REDIS_CONFIG_PORT_NAME), "6379")));
        jedisConnectionFactory.setDatabase(Integer.parseInt(StrUtils.ifEmpty(environment.getProperty(keyPrefix + "." + REDIS_CONFIG_DATABASE_NAME), "1")));
        jedisConnectionFactory.setPassword(StrUtils.ifEmpty(environment.getProperty(keyPrefix + "." + REDIS_CONFIG_PASSWORD_NAME), "123456"));
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }

4.4 测试 Demo

@RestController
public class TestController {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    @Qualifier("oneRedisTemplate")
    private RedisTemplate<String, Object> redisTemplateOne;

    @Autowired
    @Qualifier("twoRedisTemplate")
    private RedisTemplate<String, Object> redisTemplateTwo;

    @GetMapping("/test/redis/add")
    public void profileDetails() {
        redisTemplate.opsForValue().set("test1-dev1.0", "1");
        redisTemplateOne.opsForValue().set("test2-dev1.0", 2);
        redisTemplateTwo.opsForValue().set("test3-dev1.0", 3);
    }

}

浏览器输入

http://127.0.0.1:22216/test/redis/add

执行结果如下:

db1

请添加图片描述

db2

请添加图片描述

db3

请添加图片描述

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部