SpringBoot配置多个Redis集群数据源+自定义缓存注解实例

今天找了半天没找到线程的,网上都是多个Redis示例。最还还是自己想办法实现了
两个Redis集群作为数据源 + 自定义缓存注解

不会做的是否发现好tm难。都不知道怎么动手。做完之后,发现原理其实特别简单。很容易就能实现。分两部分原理和示例代码部分

原理解析:

  1. 配置两个数据源,生成两个redisTemplate (这个配置是参考我之前配置单个集群的时候,从人家的data-redis里面复制出来的,也可能是看了那篇博客。我不清楚了)
  2. 分别操作这两个tempLate.
  3. 我这里是利用AOP+注解的方式。拦截所有配置了这个注解的方法。然后先通过template请求Redis 有结果直接返回。没有就查库,然后将结果放到Redis。再返回
  4. 我这里利用两个库的用途是相同场景不同城市使用不同的Redis数据源。 有的场景是不同业务使用不同数据源。那样应该实现起来更简单

代码示例:

  1. 需要的依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  1. 注意启动类要关掉redis的自动配置
    @SpringBootApplication(exclude = {RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class})
  2. 主配置类
@Configuration
@EnableCaching
public class RedisConfig2 {
    @Autowired
    RedisClusterNode redisClusterNode;
    @Bean(name = "jtClusterRedisConnectionFactory")
    public LettuceConnectionFactory getJtRedisConnectionFactory() {
        return new LettuceConnectionFactory(new RedisClusterConfiguration(redisClusterNode.getJtNodes()));
    }
    @Bean(name = "szClusterRedisConnectionFactory")
    public LettuceConnectionFactory getSzRedisConnectionFactory() {
        return new LettuceConnectionFactory(new RedisClusterConfiguration(redisClusterNode.getSzNodes()));
    }
    @Bean(name = "redisTemplate")
    @Qualifier("jtClusterRedisConnectionFactory")
    public RedisTemplate redisTemplate(LettuceConnectionFactory jtClusterRedisConnectionFactory){
        return getRedisTemplate(jtClusterRedisConnectionFactory);
    }
    @Bean(name = "szRedisTemplate")
    @Qualifier("szClusterRedisConnectionFactory")
    public RedisTemplate szRedisTemplate(LettuceConnectionFactory szClusterRedisConnectionFactory) {
        return getRedisTemplate(szClusterRedisConnectionFactory);
    }
    private RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式,value的序列化方式采用jackson
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的key也采用String的序列化方式 value的序列化方式采用jackson
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
  1. 节点配置(这个应该可以和上面写在一起的。日后有时间在优化。将记录下来)
@Configuration
@Getter
@Setter
public class RedisClusterNode {
   @Value("${redis.cluster.jt-nodes}")
   private List<String> jtNodes;
   @Value("${redis.cluster.sz-nodes}")
   private List<String> szNodes;
}
  1. Redis集群数据源的配置(这里做了处理,总不能将公司的地址放出来把)
redis:
  cluster:
    jt-nodes: 127.0.0.1:7002,127.0.0.1:7003
    sz-nodes: 127.0.0.2:7002,127.0.0.2:7003
  1. 自定义注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCache {
    String key();
}
  1. AOP拦截使用了注解的方法
@Aspect
@Component
@Slf4j
public class RedisCacheAspect {
    @Resource(name = "szRedisTemplate")
    private RedisTemplate<String, Object> szRedisTemplate;
    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Object> jtRedisTemplate;
    @Value("${spring.profiles.active}")
    private String active;
    @Around("@annotation(com.centanet.bizcom.config.redis.MyRedisCache)")
    public Object handleCache(ProceedingJoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 取出key
        MyRedisCache myRedisCache = method.getAnnotation(MyRedisCache.class);
        String key = myRedisCache.key();
        Object[] args = joinPoint.getArgs();
        // 获取当前城市
        String city = CityHelper.getCityen();
        // 填充完整的key
        String fullKey = this.buildFullKey(key,args);
        // 先从缓存里查询。如果查询到直接返回。
        Object result = this.getObjectFromRedis(city,fullKey);
        if (!ObjectUtil.isEmpty(result)) {
            return result;
        }
        // 查询不到,走原来的方法。并且把结果填充到Redis服务器
        try {
            result = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throw new MyRedisCacheAnnotationException("自定义的Redis注解这里出问题了。问题详情"+throwable.getMessage());
        }
        if (!ObjectUtil.isEmpty(result)) {
                this.setObjectToRedis(city,fullKey,result);
        }
        return result;
    }
    private Object getObjectFromRedis(String city, String key) {
        if (city.equalsIgnoreCase("SZ")) {
            return szRedisTemplate.opsForValue().get(key);
        }
        return jtRedisTemplate.opsForValue().get(key);
    }
    private void setObjectToRedis(String city, String key, Object target) {
        if (city.equalsIgnoreCase("SZ")) {
            szRedisTemplate.opsForValue().set(key,target,6,TimeUnit.HOURS);
        }else {
            jtRedisTemplate.opsForValue().set(key,target,6,TimeUnit.HOURS);
        }
    }
    private String buildFullKey(String key, Object[] objects) {
        // 加个active的目的是因为测试环节深圳和线上是一个集群。避免数据混乱,加个个active进行区分
        StringBuilder fullKey = new StringBuilder(key).append(":").append(active);
        if (objects == null || objects.length <= 0) {
            return fullKey.toString();
        }
        for (Object o : objects) {
            fullKey.append(":").append(o.toString());
        }
        return fullKey.toString();
    }
}
  1. 使用时将注解加在方法上就好了。key看自己的需求
@MyRedisCache(key = "bizCom:AD:listSchoolRequest")
public List<SchoolResponse> listSchoolRequest(ListSchoolRequest request) {
    // 这里是一堆业务逻辑
    return null;    
}

小结

• 发现自己水平还可以哈
• 做的是否很复杂。实际弄完发现代码其实并不多

水平有限。这个之前其实就实现了多Redis数据源。但是之前把分支删除了。还好找回了。
今天完成的部分就是自定义注解和清除缓存
这次记录下。如果下次有需求直接用

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值