Springboot Redis多Db切换解决方案

本文介绍了一种在SpringBoot应用中实现Redis多数据库切换的方法,通过自定义RedisTemplate和连接工厂,以及使用RedisSerializerManager来管理不同数据库的序列化策略,确保了代码的灵活性和扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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定制序列化方案
<think>嗯,用户问的是在Spring Boot 3.3.7中替换EhCache的方案。首先,我需要回忆一下Spring Boot支持的缓存方案,尤其是现在EhCache是否还适用,或者有没有更好的替代品。 根据之前的引用,用户提到了Spring Boot 3的更新,比如Swagger改用springdoc-openapi,Redis配置路径的变化。这可能意味着在Spring Boot 3.x中,一些旧有的库可能不再被推荐使用,或者需要新的配置方式。EhCache作为传统的缓存方案,可能在Spring Boot 3.3.7中仍然可用,但用户可能想寻找其他替代方案,比如更轻量级或者性能更好的库。 首先,我应该考虑Spring Boot官方推荐的缓存解决方案。Caffeine是一个高性能的Java缓存库,被广泛认可,而且Spring Boot原生支持,配置起来应该比较方便。另外,Redis作为分布式缓存也是一个常见选择,特别是当应用需要跨多个实例共享缓存时。用户之前提到过Spring Boot 3集成Redis的配置变化,所以可能需要提醒他们注意新的配置路径,比如spring.data.redis而不是spring.redis。 然后,Hazelcast和Infinispan这两个内存数据网格,它们不仅提供缓存功能,还支持分布式计算,适合需要分布式缓存的场景。不过对于简单的应用来说,可能有点复杂。用户是否需要分布式缓存呢?可能需要根据他们的具体应用场景来决定。 还有,检查EhCache的最新版本是否兼容Spring Boot 3.3.7。EhCache 3.x版本应该支持,但用户可能因为某些原因想换掉,比如性能、特性或者维护性。这时候需要确认EhCache在Spring Boot 3中的配置是否有变化,或者是否有已知的问题。 另外,用户可能关心如何迁移现有的EhCache配置到新的缓存库。比如,从EhCache切换到Caffeine,可能需要调整依赖和配置文件,但Spring的缓存抽象层应该可以简化这个过程,因为只需更换底层的实现,而业务代码中的缓存注解(如@Cacheable)可能不需要改动。 需要提醒用户,无论选择哪种方案,都要注意依赖的兼容性。比如,Caffeine需要添加对应的starter,而Redis则需要配置连接信息。同时,配置文件的路径变化,比如从spring.redis改为spring.data.redis,这点在之前的引用中有提到,需要特别指出。 可能还需要比较各个方案的优缺点,比如本地缓存与分布式缓存的区别,内存使用情况,性能指标等。例如,Caffeine在本地缓存中性能优异,适合单实例应用,而Redis适合分布式环境,但会带来网络开销。 最后,生成相关问题的时候,应该围绕用户可能进一步询问的点,比如具体如何配置Caffeine,或者如何选择适合自己场景的缓存方案,以及性能调优的方法等。</think>在 Spring Boot 3.3.7 中替代 EhCache 的解决方案可通过以下步骤实现: ### 一、推荐替代方案 1. **Caffeine** - **高性能本地缓存**:基于 Java 8 设计,支持异步加载和自动过期策略,性能优于 EhCache 3.x - **Spring Boot 原生支持**:直接通过 `spring-boot-starter-cache` 集成 - 配置示例: ```yaml spring: cache: type: caffeine caffeine: spec: maximumSize=500,expireAfterWrite=10m ``` 2. **Redis 分布式缓存** - **跨实例共享缓存**:适用于微服务架构,支持高可用性和持久化[^2] - 依赖配置: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` - 新版配置层级调整为 `spring.data.redis`[^2] 3. **Hazelcast** - **内存数据网格**:支持分布式缓存和计算,提供 CP/AP 模式切换 - 集成步骤: ```java @Bean public HazelcastInstance hazelcastInstance() { return Hazelcast.newHazelcastInstance(); } ``` 4. **Infinispan** - **开源分布式缓存**:兼容 JCache 标准,支持事务和查询功能 - Maven 依赖: ```xml <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-spring-boot3-starter</artifactId> <version>15.0.0</version> </dependency> ``` ### 二、迁移注意事项 1. **代码层兼容性** - 保持 `@Cacheable` / `@CacheEvict` 注解无需修改 - 仅需更换底层实现库和配置文件 2. **性能对比** | 方案 | 吞吐量 (ops/ms) | 内存占用 | 适用场景 | |------------|----------------|---------|------------------| | Caffeine | 1500+ | 低 | 单机高频读操作 | | Redis | 200-500 | 中 | 分布式环境 | | Hazelcast | 800-1200 | 高 | 数据网格计算 | 3. **依赖冲突检查** 移除 EhCache 相关依赖: ```xml <!-- 删除原有依赖 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> ``` ### 三、操作验证示例(以 Caffeine 为例) 1. 启用缓存注解: ```java @SpringBootApplication @EnableCaching public class Application { /*...*/ } ``` 2. 业务层使用: ```java @Service public class ProductService { @Cacheable(value = "products", key = "#id") public Product getProductById(Long id) { // DB查询逻辑 } } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值