SpringBoot使用@Cacheable出現(xiàn)預覽工具亂碼的解決方法
直接使用注解進行緩存數據,我們再使用工具去預覽存儲的數據時發(fā)現(xiàn)是亂碼,這是由于默認序列化的問題,默認是使用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
是如何創(chuàng)建的所以省略了部分代碼
我們看到默認使用的序列化器是 JdkSerializationRedisSerializer
以上就是SpringBoot使用@Cacheable出現(xiàn)預覽工具亂碼的解決方法的詳細內容,更多關于SpringBoot使用@Cacheable出現(xiàn)亂碼的資料請關注腳本之家其它相關文章!
相關文章
Spring Boot集成Swagger2項目實戰(zhàn)
在日常的工作中,我們往往需要給前端(WEB端、IOS、Android)或者第三方提供接口,這個時候我們就需要給他們提供一份詳細的API說明文檔。這篇文章我們就來分享一種API文檔維護的方式,即通過Swagger來自動生成Restuful API文檔2018-01-01Java Swing實現(xiàn)簡單的體重指數(BMI)計算器功能示例
這篇文章主要介紹了Java Swing實現(xiàn)簡單的體重指數(BMI)計算器功能,涉及Java Swing窗口組件布局、響應及數值運算相關操作技巧,需要的朋友可以參考下2017-12-12Java中的SpringAOP、代理模式、常用AspectJ注解詳解
這篇文章主要介紹了Java中的SpringAOP、代理模式、常用AspectJ注解詳解,Spring提供了面向切面編程的豐富支持,允許通過分離應用的業(yè)務邏輯與系統(tǒng)級服務,例如審計和事務管理進行內聚性的開發(fā),需要的朋友可以參考下2023-09-09仿京東平臺框架開發(fā)開放平臺(包含需求,服務端代碼,SDK代碼)
現(xiàn)在開放平臺越來越多了,下面針對仿京東開放平臺框架,封裝自己的開放平臺,分享給大家。先感謝一下京東開放平臺的技術大佬們,下面從開放平臺需求,服務端代碼,SDK代碼三大塊進行分享2021-06-0610個實現(xiàn)Java集合,Map類型自由轉換的實用工具方法
這篇文章主要為大家整理了整理了10個實用工具方法,可以滿足?Collection、List、Set、Map?之間各種類型轉化,文中的示例代碼講解詳細,需要的可以參考下2023-09-09