Spring-IO-Caching 三中已经将缓存存入redis并从redis进行读取了,但遗留了几个问题,见图片:
1、这里为什么有一个【Empty】
Redis工具Another Redis DeskTop Manager,链接信息中的Separator默认是一个冒号。但是org.springframework.data.redis.cache.CacheKeyPrefix#SEPARATOR的却是另个冒号。
package org.springframework.data.redis.cache;
import org.springframework.util.Assert;
@FunctionalInterface
public interface CacheKeyPrefix {
String SEPARATOR = "::";
String compute(String cacheName);
static CacheKeyPrefix simple() {
return name -> name + SEPARATOR;
}
static CacheKeyPrefix prefixed(String prefix) {
Assert.notNull(prefix, "Prefix must not be null!");
return name -> prefix + name + SEPARATOR;
}
}
2、rediskey的构成
spring cache存入redis的key由以下4部分组成:
spring.cache.redis.keyPrefix
org.springframework.cache.annotation.Cacheable#cacheNames
org.springframework.data.redis.cache.CacheKeyPrefix#SEPARATOR
org.springframework.cache.annotation.Cacheable#key
。
示例值:keyPrefixcache1::key
3、存储数据是16进制不容易看
这个由于spring默认缓存使用了序列化工具: RedisSerializer.java(classLoader),代码片段如下
package org.springframework.data.redis.cache;
public class RedisCacheConfiguration {
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);
}
好搞清楚了问题及原因后,那么来解决它们吧
@Bean
public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer(CacheProperties cacheProperties) {
return (builder) -> {
//循环 为每个cache 1.重新指定序列化工具;2.重新指定缓存的key值
for (String cacheName :
cacheProperties.getCacheNames()) {
Optional<RedisCacheConfiguration> optionalRedisCacheConfiguration = builder.getCacheConfigurationFor(cacheName);
if (!optionalRedisCacheConfiguration.isPresent()) {
continue;
}
RedisCacheConfiguration redisCacheConfiguration = optionalRedisCacheConfiguration
.get()
//1.重新指定序列化工具
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()))
//2.重新指定缓存的key值
.computePrefixWith(new CacheKeyPrefix() {
String SEPARATOR = ":";
String prefix = "";
{
CacheProperties.Redis redisConfig = cacheProperties.getRedis();
if (redisConfig.isUseKeyPrefix() && StringUtils.hasLength(redisConfig.getKeyPrefix())) {
prefix = redisConfig.getKeyPrefix() + SEPARATOR;
}
}
@Override
public String compute(String cacheName) {
return prefix + cacheName + SEPARATOR;
}
});
builder.withCacheConfiguration(cacheName, redisCacheConfiguration);
}
};
}
注:本段代码仅指定了redis key的规则和value序列化方式。如果需要单独为每个cachename指定缓存时间,在这里也可以控制。
实际应用中,一个redis被多个项目公用。keyprefix可以用来区分应用,cacheName 可以用来区分项目中不同的缓存类型。具体大家可以按自己的需要来自定义
效果如下:
预告:下一篇来研究下org.springframework.cache.annotation下的注解类