题记
跟着B站的视频学着学着突然遇到版本问题,在SpringBoot1.0版本中,自定义Redis序列化操作特别简单,new一个自定义的RedisTemplate就好了,但是在SpringBoot2.0版本中,自定义Redis的序列化就变得稍微复杂一点。
出现的问题:
默认使用的序列器是JdkSerializationRedisSerializer,此序列化器导致下图结果,所以我们需要自定义序列化。
自定义序列化过程:
1. 先看默认序列化的实现
实现过程在org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration(自动配置组件)中
@Bean
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
List<String> cacheNames = cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return cacheManagerCustomizers.customize(builder.build());
}
其实这个方法的重点就在下面这句代码中:
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
分析:
在这句代码中,代码结构就是使用建造者模式,创建出一个builder对象,之后需要用这个builder对象建造我们需要用于实现序列化的RedisCacheManager对象。生成创建者时涉及到的主要对象有CacheProperties ,RedisCacheConfiguration。而这两个对象中,cacheProperties是加载配置文件中的缓存配置的,与自定义实现序列化没啥关系,关键是RedisCacheConfiguration这个对象。
看看这个类注释怎么写的
/**
* Immutable {@link RedisCacheConfiguration} helps customizing {@link RedisCache} behaviour such as caching
* {@literal null} values, cache key prefixes and binary serialization. <br />
* Start with {@link RedisCacheConfiguration#defaultCacheConfig()} and customize {@link RedisCache} behaviour from there
* on.
*
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.0
*/
简单翻译一下,RedisCacheConfiguration帮助自定义行为,如缓存值,缓存键前缀和二进制序列化。现在的任务就是搞清楚RedisCacheConfiguration实现序列化的过程,在RedisCacheConfiguration类中有两个成员变量:
private final SerializationPair<String> keySerializationPair;
private final SerializationPair<Object> valueSerializationPair;
这一看知道是用来实现序列化的,其中keySerializationPair的类型是String,valueSerializationPair的类型是Object,这就解释了为什么存入redis时,key是正常显示,而value是看不懂的转译后的序列字节码。所以我们需要自定义值的序列化。在类RedisCacheConfiguration中有一个serializeValuesWith方法,这个方法就实现了值序列化的过程。
public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSerializationPair) {
Assert.notNull(valueSerializationPair, "ValueSerializationPair must not be null!");
//返回一个RedisCacheConfiguration对象,其中的valueSerializationPair是由参数传入的SerializationPair对象
return new RedisCacheConfiguration(ttl, cacheNullValues, usePrefix, keyPrefix, keySerializationPair,
valueSerializationPair, conversionService);
}
在SerializationPair对象中有一个静态代码块,使用了适配器模式,提供了我们自定义序列化器的接口,我们只要把自定义的序列化器传进去就可以实现自定义序列化了。
/**
* Creates a {@link SerializationPair} adapter given {@link RedisSerializer}.
*
* @param serializer must not be {@literal null}.
* @return a {@link SerializationPair} adapter for {@link RedisSerializer}.
*/
static <T> SerializationPair<T> fromSerializer(RedisSerializer<T> serializer) {
Assert.notNull(serializer, "RedisSerializer must not be null!");
return new RedisSerializerToSerializationPairAdapter<>(serializer);
}
2.自定义序列化
1.实现自定义RedisCacheConfiguration:
@Bean
public RedisCacheConfiguration myRedisCacheConfiguration() {
//使用json序列化器
RedisSerializer<Object> jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//将选用的自定义序列化器传入SerializationPair.fromSerializer这个静态代码块中,从而得到一个SerializationPair
RedisSerializationContext.SerializationPair<Object> serializationPair = RedisSerializationContext.SerializationPair
.fromSerializer(jackson2JsonRedisSerializer);
//将SerializationPair用于存入Redis中值的序列化
return RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(serializationPair);
}
2. 实现自定义RedisCacheManager:
@Bean
public RedisCacheManager myCacheManager(RedisConnectionFactory redisConnectionFactory) {
//把前面自定义好的myRedisCacheConfiguration作为参数传入,最后使用创建者模式返回RedisCacheManager对象,实现自定义序列化
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory).cacheDefaults(myRedisCacheConfiguration());
RedisCacheManager cm = builder.build();
return cm;
}