SpringBoot使用@Cacheable出現(xiàn)預(yù)覽工具亂碼的解決方法
直接使用注解進(jìn)行緩存數(shù)據(jù),我們?cè)偈褂霉ぞ呷ヮA(yù)覽存儲(chǔ)的數(shù)據(jù)時(shí)發(fā)現(xiàn)是亂碼,這是由于默認(rèn)序列化的問(wèn)題,默認(rèn)是使用JdkSerializationRedisSerializer
,我們將其更改即可
解決辦法
我們重新定義一個(gè)org.springframework.data.redis.cache.RedisCacheConfiguration
的Bean,并修改序列化器即可
/** * 此類解決 @Cacheable 存入的緩存使用預(yù)覽工具時(shí)亂碼問(wèn)題 * * @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(); // 工具預(yù)覽亂碼問(wèn)題 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方式存儲(chǔ)的緩存需要清理掉。否則會(huì)因?yàn)樾蛄谢?反序列化方式不一致而導(dǎo)致錯(cuò)誤
源碼導(dǎo)讀
RedisCache#put
找到 org.springframework.data.redis.cache.RedisCache#put
方法。這個(gè)方法就是最終存入的方法
/* * (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; }
這個(gè)變量就是最終決定序列化的類了,如何設(shè)置呢?在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); }
默認(rèn)的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(); // 重點(diǎn) 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)建的所以省略了部分代碼
我們看到默認(rèn)使用的序列化器是 JdkSerializationRedisSerializer
以上就是SpringBoot使用@Cacheable出現(xiàn)預(yù)覽工具亂碼的解決方法的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot使用@Cacheable出現(xiàn)亂碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot集成Swagger2項(xiàng)目實(shí)戰(zhàn)
在日常的工作中,我們往往需要給前端(WEB端、IOS、Android)或者第三方提供接口,這個(gè)時(shí)候我們就需要給他們提供一份詳細(xì)的API說(shuō)明文檔。這篇文章我們就來(lái)分享一種API文檔維護(hù)的方式,即通過(guò)Swagger來(lái)自動(dòng)生成Restuful API文檔2018-01-01Java Swing實(shí)現(xiàn)簡(jiǎn)單的體重指數(shù)(BMI)計(jì)算器功能示例
這篇文章主要介紹了Java Swing實(shí)現(xiàn)簡(jiǎn)單的體重指數(shù)(BMI)計(jì)算器功能,涉及Java Swing窗口組件布局、響應(yīng)及數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-12-12JAVA操作MongoDB數(shù)據(jù)庫(kù)實(shí)例教程
MongoDB是一個(gè)文檔型數(shù)據(jù)庫(kù),是NOSQL家族中最重要的成員之一,下面這篇文章主要給大家介紹了關(guān)于JAVA操作MongoDB數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05Java中的SpringAOP、代理模式、常用AspectJ注解詳解
這篇文章主要介紹了Java中的SpringAOP、代理模式、常用AspectJ注解詳解,Spring提供了面向切面編程的豐富支持,允許通過(guò)分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù),例如審計(jì)和事務(wù)管理進(jìn)行內(nèi)聚性的開(kāi)發(fā),需要的朋友可以參考下2023-09-09SpringBoot事務(wù)使用及回滾實(shí)現(xiàn)代碼詳解
這篇文章主要介紹了SpringBoot事務(wù)使用及回滾實(shí)現(xiàn)代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08MyBatis-Plus數(shù)據(jù)庫(kù)配置與數(shù)據(jù)源整合方案
本文詳細(xì)介紹了在MyBatis-Plus中進(jìn)行數(shù)據(jù)庫(kù)配置與數(shù)據(jù)源整合的常見(jiàn)方法,包括單數(shù)據(jù)源和多數(shù)據(jù)源的配置步驟,以及如何使用SpringBoot的自動(dòng)配置和手動(dòng)配置來(lái)管理數(shù)據(jù)源,通過(guò)合理的配置,開(kāi)發(fā)者可以簡(jiǎn)化數(shù)據(jù)庫(kù)操作,實(shí)現(xiàn)高效的數(shù)據(jù)庫(kù)管理和復(fù)雜的應(yīng)用架構(gòu)2025-02-02仿京東平臺(tái)框架開(kāi)發(fā)開(kāi)放平臺(tái)(包含需求,服務(wù)端代碼,SDK代碼)
現(xiàn)在開(kāi)放平臺(tái)越來(lái)越多了,下面針對(duì)仿京東開(kāi)放平臺(tái)框架,封裝自己的開(kāi)放平臺(tái),分享給大家。先感謝一下京東開(kāi)放平臺(tái)的技術(shù)大佬們,下面從開(kāi)放平臺(tái)需求,服務(wù)端代碼,SDK代碼三大塊進(jìn)行分享2021-06-0610個(gè)實(shí)現(xiàn)Java集合,Map類型自由轉(zhuǎn)換的實(shí)用工具方法
這篇文章主要為大家整理了整理了10個(gè)實(shí)用工具方法,可以滿足?Collection、List、Set、Map?之間各種類型轉(zhuǎn)化,文中的示例代碼講解詳細(xì),需要的可以參考下2023-09-09