SpringBoot使用@Cacheable出现预览工具乱码的解决方法
作者:逆水行舟x
直接使用注解进行缓存数据,我们再使用工具去预览存储的数据时发现是乱码,这是由于默认序列化的问题,默认是使用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
以上就是SpringBoot使用@Cacheable出现预览工具乱码的解决方法的详细内容,更多关于SpringBoot使用@Cacheable出现乱码的资料请关注脚本之家其它相关文章!