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 + "::";
};
}
}