Springboot Redis多Db切换解决方案

Springboot Redis多Db切换解决方案

1.问题描述
2.解决思路
3.解决问题
4.使用方法

1.问题描述

一个需求,需要一个组件对接redis,需要支持多个DB的切换,以及序列化和反序列的管理,并且不对以往代码造成影响,且可以支持SPI形式的接入.

2.解决思路

  • 1.需要支持多个DB的话,那么切换DB的时候不能对其他的线程造成影响,结果应该是一个线程在连接池中获取到对应的DB链接,操作完成之后把链接放回线程池.
  • 2.这样在实现的时候应该使用一个Map结构存储线程和dbIndex的关系.
  • 3.自行实现一个链接池
  • 4.代价太大
  • 5.换一个思路,实现多个RedisTemplate,但是RedisTemplate并不持有链接本身,仅仅持有一个Factory.
  • 6.那么实现多个Factory,让每个Factory对应不同的dbIndex.
  • 7.淦

3.解决问题

声明一个Enable注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Import({RedisBeanAutoConfig.class})
public @interface EnableRedisDbs {
}

用Import注入Bean

@Slf4j
@Component
public class RedisBeanAutoConfig {

    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    @ConditionalOnMissingBean(RedisSerializerManager.class)
    public RedisSerializerManager getRedisSerializerManager(){
        return new RedisSerializerManager();
    }

    @Bean
    public RedisDbsTemplate redisDbsEntity(Environment environment, RedisSerializerManager redisSerializerManager, ApplicationContext applicationContext){
        LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
        return new RedisDbsTemplate(environment, connectionFactory,redisSerializerManager,applicationContext);
    }

}

使用2.X原本的Lettuce链接池,并且取出它里面的配置文件

@Slf4j
public class RedisDbsTemplate {
    private final static Map<Integer, RedisTemplate> redisTemplateMap = new HashMap<Integer, RedisTemplate>();

    private Environment environment;

    private LettuceConnectionFactory connectionFactory;

    private RedisSerializerManager redisSerializerManager;

    private DefaultListableBeanFactory beanFactory;

    public RedisDbsTemplate(Environment environment, LettuceConnectionFactory connectionFactory, RedisSerializerManager redisSerializerManager, ApplicationContext applicationContext){
        this.environment=environment;
        this.connectionFactory=connectionFactory;
        this.redisSerializerManager=redisSerializerManager;
        this.beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        init();
    }

    private void init() {
        String property = environment.getProperty("spring.redis.databases");
        String beanPrefix = environment.getProperty("spring.redis.beanPrefix","redis_db_");
        if (StringUtils.isEmpty(property)) {
            log.warn("'spring.redis.databases' No settings");
            return;
        }
        String[] dbs = property.split(",");
        for (String db : dbs) {
            int dbIndex = NumberUtils.toInt(db);
            RedisTemplateBuilder redisTemplateBuilder = new RedisTemplateBuilder(dbIndex, connectionFactory,redisSerializerManager);
            RedisTemplate redisTemplate = redisTemplateBuilder.builder();
            redisTemplateMap.put(dbIndex,redisTemplate);

            //动态注入到Spring的BeanFactory
            this.beanFactory.registerSingleton(beanPrefix+db,redisTemplate);
        }
    }

    public RedisTemplate getRedisTemplate(int i){
        return redisTemplateMap.get(i);
    }
}

生成一个RedisDbsTemplate Bean,并且把小的RedisTemplate指定名称注入到BeanFactory中

public class RedisTemplateBuilder {

    private int dbIndex;

    private LettuceConnectionFactory connectionFactory;

    private RedisSerializerManager.RedisSerializerEntity redisSerializerEntity= RedisSerializerManager.getDefKeyValueSerializer();

    public RedisTemplateBuilder(int dbIndex, LettuceConnectionFactory connectionFactory, RedisSerializerManager redisSerializerManager) {
        this.dbIndex = dbIndex;
        this.connectionFactory = connectionFactory;
        RedisSerializerManager.RedisSerializerEntity redisSerializerEntity = redisSerializerManager.get(dbIndex);
        if (redisSerializerEntity !=null) {
            this.redisSerializerEntity= redisSerializerEntity;
        }
    }

    public RedisTemplate builder() {
        RedisTemplate<Serializable, Object> redisTemplate = new RedisTemplate<Serializable, Object>();
        RedisConnectionFactory factory = this.getFactory(dbIndex);
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(redisSerializerEntity.getKeySerializer());
        redisTemplate.setValueSerializer(redisSerializerEntity.getValueSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    private RedisConnectionFactory getFactory(int i) {
        RedisStandaloneConfiguration standaloneConfiguration = connectionFactory.getStandaloneConfiguration();
        standaloneConfiguration.setDatabase(i);
        LettuceClientConfiguration clientConfiguration = connectionFactory.getClientConfiguration();
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(standaloneConfiguration, clientConfiguration);
        lettuceConnectionFactory.afterPropertiesSet();
        return lettuceConnectionFactory;
    }

}

声明一个序列化管理的类

public class RedisSerializerManager {

    /**
     * 默认的序列化方案
     */
    private static RedisSerializer defRedisSerializer;
    /**
     * 默认的序列化方案
     */
    private static RedisSerializerEntity defKeyValueSerializer;

    static {
        defRedisSerializer = new StringRedisSerializer();
        defKeyValueSerializer = new RedisSerializerEntity();
        defKeyValueSerializer.setKeySerializer(defRedisSerializer);
        defKeyValueSerializer.setValueSerializer(defRedisSerializer);
    }

    private Map<Integer, RedisSerializerEntity> serializerMap = new HashMap<>();

    public static RedisSerializerEntity getDefKeyValueSerializer() {
        return defKeyValueSerializer;
    }

    public static void setDefKeyValueSerializer(RedisSerializerEntity defKeyValueSerializer) {
        RedisSerializerManager.defKeyValueSerializer = defKeyValueSerializer;
    }

    /**
     * @param dbIndex               dbIndex
     * @param redisSerializerEntity
     */
    public void put(Integer dbIndex, RedisSerializerEntity redisSerializerEntity) {
        serializerMap.put(dbIndex, redisSerializerEntity);
    }

    public RedisSerializerEntity get(Integer dbIndex) {
        return serializerMap.get(dbIndex);
    }

    public static RedisSerializer getDefRedisSerializer() {
        return defRedisSerializer;
    }

    public static void setDefRedisSerializer(RedisSerializer defRedisSerializer) {
        RedisSerializerManager.defRedisSerializer = defRedisSerializer;
    }

    /**
     * key和value的序列化方案组
     */
    public static class RedisSerializerEntity {
        /**
         * key的序列化方案
         */
        private RedisSerializer<?> keySerializer = defRedisSerializer;

        /**
         * value的序列化方案
         */
        private RedisSerializer<?> valueSerializer = defRedisSerializer;

        public RedisSerializer<?> getKeySerializer() {
            return keySerializer;
        }

        public void setKeySerializer(RedisSerializer<?> keySerializer) {
            this.keySerializer = keySerializer;
        }

        public RedisSerializer<?> getValueSerializer() {
            return valueSerializer;
        }

        public void setValueSerializer(RedisSerializer<?> valueSerializer) {
            this.valueSerializer = valueSerializer;
        }
    }
}

4.使用方法

    1.注解@EnableRedisDbs(可以修改为META-INF方案)
    2.配置spring.redis.databases
        内容为db的index使用','间隔
    3.配置spring.redis.beanPrefix
        用于按名称注入redistemplate的前缀,默认'redis_db_'
    4.注入RedisDbsTemplate,使用时getRedisTemplate(dbIndex);
    5.使用
        @Autowired
        @Qualifier("redis_db_X")
        private RedisTemplate redisTemplate;
      X为dbIndex;
    6.使用RedisSerializerManager为每一个DB_redisTemplate定制序列化方案

你可能感兴趣的:(Redis,Java,SpringBoot,java,redis,spring)