Spring @Cacheable生成的redisKey,出现两个连续的冒号::

1、参考

基于redis2.1.6实现spring cache生成的key多出一个冒号

2、解决

需要对key进行处理,【重点】是computePrefixWith方法

   config = config.computePrefixWith(cacheName -> {
       return cacheName + StrUtil.COLON;
   });

2.1 常见的解决办法

    @Bean
    @Primary
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 设置使用 : 单冒号,而不是双 :: 冒号,避免 Redis Desktop Manager 多余空格
        // 详细可见 https://blog.csdn.net/chuixue24/article/details/103928965 博客
        // 再次修复单冒号,而不是双 :: 冒号问题,Issues 详情:https://gitee.com/zhijiantianya/yudao-cloud/issues/I86VY2
        config = config.computePrefixWith(cacheName -> {
            String keyPrefix = cacheProperties.getRedis().getKeyPrefix();
            if (StringUtils.hasText(keyPrefix)) {
                keyPrefix = keyPrefix.lastIndexOf(StrUtil.COLON) == -1 ? keyPrefix + StrUtil.COLON : keyPrefix;
                return keyPrefix + cacheName + StrUtil.COLON;
            }
            return cacheName + StrUtil.COLON;
        });
        // 设置使用 JSON 序列化方式
        config = config.serializeValuesWith(
                RedisSerializationContext.SerializationPair.fromSerializer(buildRedisSerializer()));

        // 设置 CacheProperties.Redis 的属性
        CacheProperties.Redis redisProperties = cacheProperties.getRedis();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }

2.2 本人的解决

以下是完整代码
调用computePrefixWith方法,重新定义key的名称

    private RedisCacheConfiguration getRedisCacheConfiguration(Duration duration) {
        RedisCacheConfiguration config = RedisCacheConfiguration
                .defaultCacheConfig()
                .entryTtl(duration)
                // .disableCachingNullValues()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        config = config.computePrefixWith(cacheName -> {
            // keyPrefix是cacheProperties设置的的redis前缀,一点小优化
            String keyPrefix = cacheProperties.getRedis().getKeyPrefix();
            if (StringUtils.hasText(keyPrefix)) {
                keyPrefix = keyPrefix.lastIndexOf(StrUtil.COLON) == -1 ? keyPrefix + StrUtil.COLON : keyPrefix;
                return keyPrefix + cacheName + StrUtil.COLON;
            }
            //重点是这句
            return cacheName + StrUtil.COLON;
        });

        return config;
    }

3、排查

在@Cacheable生成缓存key时,总是产生sys:cache:user::admin,多出两个冒号的情况

    @Override
    @Cacheable(cacheNames = CacheConstant.SYS_USERS_CACHE, key = "#username")
    public LoginUser getUserByName(String username) {
        if (org.jeecg.framework.common.util.CN.isEmpty(username)) {
            return null;
        }
        LoginUser loginUser = new LoginUser();
        SysUser sysUser = userMapper.getUserByName(username);
        if (sysUser == null) {
            return null;
        }
        BeanUtils.copyProperties(sysUser, loginUser);
        return loginUser;
    }

经过查看源码,发现defaultCacheConfig()生成的RedisCacheConfiguration对象,生成key的参数是CacheKeyPrefix.simple()

    public static RedisCacheConfiguration defaultCacheConfig() {
        return defaultCacheConfig((ClassLoader)null);
    }

    public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        registerDefaultConverters(conversionService);
        return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(), SerializationPair.fromSerializer(RedisSerializer.string()), SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
    }

simple()方法中,String SEPARATOR = "::"; 明确是两个冒号,终于找到原因了

@FunctionalInterface
public interface CacheKeyPrefix {
    String SEPARATOR = "::";

    String compute(String cacheName);

    static CacheKeyPrefix simple() {
        return (name) -> {
            return name + "::";
        };
    }

    static CacheKeyPrefix prefixed(String prefix) {
        Assert.notNull(prefix, "Prefix must not be null!");
        return (name) -> {
            return prefix + name + "::";
        };
    }
}
posted @ 2024-07-30 17:40  一只桔子2233  阅读(6)  评论(0编辑  收藏  举报