SpringBoot自定義Redis實現緩存序列化詳解
剛剛完成瞭Spring Boot整合Redis進行瞭數據的緩存管理,但緩存管理的實體類數據使用的是JDK序列化方式,不便於使用可視化管理工具進行查看和管理。
接下來分別針對基於註解的Redis緩存實現和基於API的Redis緩存實現中的數據序列化機制進行介紹,並自定義JSON格式的數據序列化方式進行數據緩存管理
1、自定義RedisTemplate
1.1、Redis API默認序列化機制
基於API的Redis緩存實現是使用RedisTemplate模板進行數據緩存操作的,這裡打開RedisTemplate類,查看該類的源碼信息
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { // 聲明瞭key、value的各種序列化方式,初始值為空 @Nullable private RedisSerializer keySerializer = null; @Nullable private RedisSerializer valueSerializer = null; @Nullable private RedisSerializer hashKeySerializer = null; @Nullable private RedisSerializer hashValueSerializer = null; ... // 進行默認序列化方式設置,設置為JDK序列化方式 public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if (this.defaultSerializer == null) { this.defaultSerializer = new JdkSerializationRedisSerializer( this.classLoader != null ? this.classLoader : this.getClass().getClassLoader()); } ... } ... }
從上述RedisTemplate核心源碼可以看出,在RedisTemplate內部聲明瞭緩存數據key、value的各種序列化方式,且初始值都為空;在afterPropertiesSet()方法中,判斷如果默認序列化參數defaultSerializer為空,將數據的默認序列化方式設置為JdkSerializationRedisSerializer
根據上述源碼信息的分析,可以得到以下兩個重要的結論:
(1)使用RedisTemplate進行Redis數據緩存操作時,內部默認使用的是JdkSerializationRedisSerializer序列化方式,所以進行數據緩存的實體類必須實現JDK自帶的序列化接口(例如Serializable);
(2)使用RedisTemplate進行Redis數據緩存操作時,如果自定義瞭緩存序列化方式defaultSerializer,那麼將使用自定義的序列化方式。
另外,在RedisTemplate類源碼中,看到的緩存數據key、value的各種序列化類型都是RedisSerializer。進入RedisSerializer源碼查看RedisSerializer支持的序列化方式(進入該類後,使用Ctrl+Alt+左鍵單擊類名查看)
可以看出,RedisSerializer是一個Redis序列化接口,默認有6個實現類,這6個實現類代表瞭6種不同的數據序列化方式。其中,JdkSerializationRedisSerializer是JDK自帶的,也是RedisTemplate內部默認使用的數據序列化方式,開發者可以根據需要選擇其他支持的序列化方式(例如JSON方式)
1.2、自定義RedisTemplate序列化機制
在項目中引入Redis依賴後,Spring Boot提供的RedisAutoConfiguration自動配置會生效。打開RedisAutoConfiguration類,查看內部源碼中關於RedisTemplate的定義方式
public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean( name = {"redisTemplate"} ) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } ... }
從上述RedisAutoConfiguration核心源碼中可以看出,在Redis自動配置類中,通過Redis連接工廠RedisConnectionFactory初始化瞭一個RedisTemplate;該類上方添加瞭@ConditionalOnMissingBean註解(顧名思義,當某個Bean不存在時生效),用來表明如果開發者自定義瞭一個名為redisTemplate的Bean,則該默認初始化的RedisTemplate不會生效。
如果想要使用自定義序列化方式的RedisTemplate進行數據緩存操作,可以參考上述核心代碼創建一個名為redisTemplate的Bean組件,並在該組件中設置對應的序列化方式即可
接下來,在項目中創建名為com.lagou.config的包,在該包下創建一個Redis自定義配置類RedisConfig,並按照上述思路自定義名為redisTemplate的Bean組件
@Configuration public class RedisConfig { // 自定義RedisTemplate @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); // 創建一個JSON格式序列化對象,對緩存數據的key和value進行轉換 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // 解決查詢緩存轉換異常的問題 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 設置RedisTemplate模板api序列化方式為json template.setDefaultSerializer(jackson2JsonRedisSerializer); return template; } }
通過@Configuration註解定義瞭一個RedisConfig配置類,並使用@Bean註解註入瞭一個默認名稱為方法名的redisTemplate組件(註意,該Bean組件名稱必須是redisTemplate)。在定義的Bean組件中,自定義瞭一個RedisTemplate,使用自定義的Jackson2JsonRedisSerializer數據序列化方式;在定制序列化方式中,定義瞭一個ObjectMapper用於進行數據轉換設置
1.3、效果測試
可以看出,執行findById()方法正確查詢出用戶評論信息Comment,重復進行同樣的查詢操作,數據庫隻執行瞭一次SQL語句,這說明定制的Redis緩存生效。
使用Redis客戶端可視化管理工具Redis Desktop Manager查看緩存數據 :
執行findById()方法查詢出用戶評論信息Comment正確存儲到瞭Redis緩存庫中,且緩存到Redis服務的數據已經使用瞭JSON格式存儲展示,查看和管理也非常方便,說明自定義的Redis API模板工具RedisTemplate生效
2、自定義RedisCacheManager
剛剛針對基於 API方式的RedisTemplate進行瞭自定義序列化方式的改進,從而實現瞭JSON序列化方式緩存數據,但是這種自定義的RedisTemplate對於基於註解的Redis緩存來說,是沒有作用的。
接下來,針對基於註解的Redis緩存機制和自定義序列化方式進行講解
2.1、Redis註解默認序列化機制
打開Spring Boot整合Redis組件提供的緩存自動配置類RedisCacheConfiguration(org.springframework.boot.autoconfigure.cache包下的),查看該類的源碼信息,其核心代碼如下
@Configuration class RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) { RedisCacheManagerBuilder builder = RedisCacheManager .builder(redisConnectionFactory) .cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader())); List<String> cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet(cacheNames)); } return (RedisCacheManager) this.customizerInvoker.customize(builder.build()); } private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(ClassLoader classLoader) { if (this.redisCacheConfiguration != null) { return this.redisCacheConfiguration; } else { Redis redisProperties = this.cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(SerializationPair.fromSerializer( new JdkSerializationRedisSerializer(classLoader))); ... return config; } } }
從上述核心源碼中可以看出,同RedisTemplate核心源碼類似,RedisCacheConfiguration內部同樣通過Redis連接工廠RedisConnectionFactory定義瞭一個緩存管理器RedisCacheManager;同時定制RedisCacheManager時,也默認使用瞭JdkSerializationRedisSerializer序列化方式。
如果想要使用自定義序列化方式的RedisCacheManager進行數據緩存操作,可以參考上述核心代碼創建一個名為cacheManager的Bean組件,並在該組件中設置對應的序列化方式即可
註意,在Spring Boot 2.X版本中,RedisCacheManager是單獨進行構建的。因此,在SpringBoot 2.X版本中,對RedisTemplate進行自定義序列化機制構建後,仍然無法對RedisCacheManager內部默認序列化機制進行覆蓋(這也就解釋瞭基 於註解的Redis緩存實現仍然會使用JDK默認序列化機制的原因),想要基於註解的Redis緩存實現也使用自定義序列化機制,需要自定義RedisCacheManager
2.2、自定義RedisCacheManager
在項目的Redis配置類RedisConfig中,按照上一步分析的定制方法自定義名為cacheManager的Bean組件
@Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 分別創建String和JSON格式序列化對象,對緩存數據key和value進行轉換 RedisSerializer<String> strSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer(Object.class); // 解決查詢緩存轉換異常的問題 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); // 上面註釋過時代碼的替代方法 jacksonSerial.setObjectMapper(om); // 定制緩存數據序列化方式及時效 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofDays(1)) // 設置緩存數據的時效(設置為瞭1天) .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(strSerializer)) // 對當前對象的key使用strSerializer這個序列化對象,進行轉換 .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(jacksonSerial)) // 對value使用jacksonSerial這個序列化對象,進行轉換 .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager .builder(redisConnectionFactory).cacheDefaults(config).build(); return cacheManager; }
上述代碼中,在RedisConfig配置類中使用@Bean註解註入瞭一個默認名稱為方法名的cacheManager組件。在定義的Bean組件中,通過RedisCacheConfiguration對緩存數據的key和value分別進行瞭序列化方式的定制,其中緩存數據的key定制為StringRedisSerializer(即String格式),而value定制為瞭Jackson2JsonRedisSerializer(即JSON格式),同時還使用entryTtl(Duration.ofDays(1))方法將緩存數據有效期設置為1天
完成基於註解的Redis緩存管理器RedisCacheManager定制後,可以對該緩存管理器的效果進行測試(使用自定義序列化機制的RedisCacheManager測試時,實體類可以不用實現序列化接口)
到此這篇關於SpringBoot自定義Redis實現緩存序列化詳解的文章就介紹到這瞭,更多相關SpringBoot 緩存序列化內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- SpringBoot結合Redis實現序列化的方法詳解
- 為Java項目添加Redis緩存的方法
- 使用註解實現Redis緩存功能
- 一起來看看springboot集成redis的使用註解
- Java SpringCache+Redis緩存數據詳解