Springboot RedisマルチDbスイッチングソリューション


Springboot RedisマルチDbスイッチングソリューション
1.問題の説明2.解決構想3.問題を解決する使用方法
1.問題の説明
1つのニーズは、1つのコンポーネントがredisに接続する必要があり、複数のDBの切り替えをサポートする必要があり、シーケンス化と逆シーケンスの管理が必要であり、従来のコードに影響を与えることなく、SPI形式のアクセスをサポートすることができる.
2.解決の考え方
  • 1.複数のDBをサポートする必要がある場合、DBを切り替える際に他のスレッドに影響を与えることができず、結果として1つのスレッドが接続プールで対応するDBリンクを取得し、操作が完了するとリンクをスレッドプールに戻す.
  • 2.このように実装には、1つのMap構造を用いるスレッドとdbIndexとの関係を記憶すべきである.
  • 3.リンクプール
  • を独自に実装
  • 4.代価が大きすぎる
  • 5.考え方を変えて複数のRedisTemplateを実現するが、RedisTemplateはリンクそのものを持たず、Factoryを1つしか持たない.
  • 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