直接使用注解进行缓存数据,我们再使用工具去预览存储的数据时发现是乱码,这是由于默认序列化的问题,默认是使用JdkSerializationRedisSerializer
,我们将其更改即可
解决办法
我们重新定义一个org.springframework.data.redis.cache.RedisCacheConfiguration
的Bean,并修改序列化器即可
/**
* 此类解决 @Cacheable 存入的缓存使用预览工具时乱码问题
*
* @author YinShangwen
* @since 2023/10/5 14:02
*/
@Configuration
public class RedisCacheConfig {
@Bean
public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 工具预览乱码问题
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
⚠️
注意:如果之前有@Cacheable方式存储的缓存需要清理掉。否则会因为序列化/反序列化方式不一致而导致错误
源码导读
RedisCache#put
找到 org.springframework.data.redis.cache.RedisCache#put
方法。这个方法就是最终存入的方法
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object)
*/
@Override
public void put(Object key, @Nullable Object value) {
Object cacheValue = preProcessCacheValue(value);
if (!isAllowNullValues() && cacheValue == null) {
throw new IllegalArgumentException(String.format(
"Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.",
name));
}
cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
}
serializeCacheValue
我们注意到serializeCacheValue(cacheValue)
private final RedisCacheConfiguration cacheConfig;
/**
* Serialize the value to cache.
*
* @param value must not be {@literal null}.
* @return never {@literal null}.
*/
protected byte[] serializeCacheValue(Object value) {
if (isAllowNullValues() && value instanceof NullValue) {
return BINARY_NULL_VALUE;
}
return ByteUtils.getBytes(cacheConfig.getValueSerializationPair().write(value));
}
getValueSerializationPair
再看 cacheConfig.getValueSerializationPair()
是什么
private final SerializationPair<Object> valueSerializationPair;
/**
* @return never {@literal null}.
*/
public SerializationPair<Object> getValueSerializationPair() {
return valueSerializationPair;
}
这个变量就是最终决定序列化的类了,如何设置呢?在RedisCacheConfiguration
中有如下方法
/**
* Define the {@link SerializationPair} used for de-/serializing cache values.
*
* @param valueSerializationPair must not be {@literal null}.
* @return new {@link RedisCacheConfiguration}.
*/
public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSerializationPair) {
Assert.notNull(valueSerializationPair, "ValueSerializationPair must not be null!");
return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
}
默认的RedisCacheConfiguration如何被装载
找到类org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
注意:类名相同但包路径不相同
org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
org.springframework.data.redis.cache.RedisCacheConfiguration
class RedisCacheConfiguration {
...
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
CacheProperties cacheProperties, ClassLoader classLoader) {
Redis redisProperties = cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
// 重点
config = config.serializeValuesWith(
SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
我们只看org.springframework.data.redis.cache.RedisCacheConfiguration
是如何创建的所以省略了部分代码
我们看到默认使用的序列化器是 JdkSerializationRedisSerializer
🎉
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/195211.html