基於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; } ... }
@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 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
在项目的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實作快取序列化的詳細內容。更多資訊請關注PHP中文網其他相關文章!