spring boot 自动配置的缓存序列化为 JdkSerializationRedisSerializer ,缺点大家都懂,占用过多空间,跨平台困难,可读信差,所以把他换成json的序列化方式。
当然,spring boot 也已经准备了JSON的序列化器GenericJackson2JsonRedisSerializer , Jackson2JsonRedisSerializer
但是,这些我们通通不用,本文将自义定一个序列化器,使用fastjson来将数据转换为json
============================我是分割线=========================================================
首先按照spring boot的一贯尿性,配置类名字都叫 xxxxxConfiguration,果不其然:
自动配置,默认帮我配置的redisCache 在类RedisCacheConfiguration中。
该配置类打上了 @ConditionalOnMissingBean({CacheManager.class})注解,表示了,如果我们没有向ioc容器中注入CacheManager类,就自动创建该配置类。所以我们自定义CacheManager 只需直接注入ioc容器就会覆盖默认配置
然后往下看,默认spring boot是如何创建CacheManager的,方便我们copy
这就是spring boot 帮我们生成的CacheManager,先二话不说直接copy到我们自定义的配置类中
@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()); }
这一段从配置文件中初始化,已经设置好的缓存,我们可以先不要。
List<String> cacheNames = this.cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet(cacheNames)); }
这段创建了CacheManager对象,并且设置了一些配置,为了方便观看,把它拆开写
RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader()));
所以最后copy下来的代码是这个样子的
@Bean
public RedisCacheManager cust_cacheManager(RedisConnectionFactory redisConnectionFactory) {
//redis默认配置文件
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
//RedisCacheManager 生成器创建
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration);
return builder.build();
}
RedisCacheConfiguration 为redisCache的自定义设置类 他和上文提高的 RedisCacheConfiguration 不是一个类,前者所在包为org.springframework.data.redis.cache,后者所在包为 org.springframework.boot.autoconfigure.cache
进入该类有:
private final Duration ttl; //过期时间 private final boolean cacheNullValues; //缓存是否为null private final CacheKeyPrefix keyPrefix; private final boolean usePrefix; private final SerializationPair<String> keySerializationPair; //key的序列化器 private final SerializationPair<Object> valueSerializationPair; //value的序列化器 private final ConversionService conversionService;
所以很简单,只要设置了该类的属性,就能改变manager的一些配置。如:过期时间,以及序列化器
但是注意,该类的属性都是final类型无法修改,所以我们看该类的设置值的方法
public RedisCacheConfiguration entryTtl(Duration ttl) { Assert.notNull(ttl, "TTL duration must not be null!"); return new RedisCacheConfiguration(ttl, this.cacheNullValues, this.usePrefix, this.keyPrefix, this.keySerializationPair, this.valueSerializationPair, this.conversionService); }
这个看名字是 设置过期时间,在该方法内部,他没有直接改变属性的值,而是把之前设置的值和本次需要改变的值一起拿来,new了一个新的对象。
所以正确的设置姿势应该是这样的:
@Bean
public RedisCacheManager cust_cacheManager(RedisConnectionFactory redisConnectionFactory) {
//redis默认配置文件
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1));
//RedisCacheManager 生成器创建
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration);
return builder.build();
}
同理我们要改变序列化器为fastjson 也只要设置值valueSerializationPair就可以了
回到自动配置的 RedisCacheConfiguration 类,我们看看spring boot是怎么创建序列化对象的
点进去发现JdkSerializationRedisSerializer是RedisSerializer接口的实现类
总的来说 很简单,创建一个RedisSerializer接口的对象,然后用SerializationPair.fromSerializer封装一下,就能直接扔配置文件里了
查看RedisSerializer接口的现实关系
本文开头提到的 GenericJackson2JsonRedisSerializer , Jackson2JsonRedisSerializer 这些Spring boot 默认的JSON序列化器就在这里。如果不想自定义fastjson 序列化器,那么直接把这2个类的其中一个 设置进valueSerializationPair 就可以实现json 序列化了
============================我是分割线=========================================================
创建一个类 实现RedisSerializer接口,我这里名字叫FastJsonRedisSerializer
他将重写2个方法,看名字也知道,一个是序列化,一个是反序列化。
@Nullable
byte[] serialize(@Nullable T var1) throws SerializationException;
@Nullable
T deserialize(@Nullable byte[] var1) throws SerializationException;
fastjson序列化,反序列化方法很简单,这里就不多说了 直接上代码
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
try {
return JSON.toJSONBytes(t, SerializerFeature.WriteClassName);
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex);
}
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
String data =new String(bytes);
T result = (T)JSON.parse(data);
return result;
}
这里注意的是,序列化的时候,我设置了 SerializerFeature.WriteClassName,这会讲泛型T的类型写入JSON中多了一个@type的属性,来存储类型,这样反序列化的时候就能自动转成原本的类型
同时需要在spring boot中全局设置 ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
获得序列化器后把它设置进manager中
最终的配置为:
@Bean
public RedisCacheManager cust_cacheManager(RedisConnectionFactory redisConnectionFactory) {
//创建自定义序列化器
FastJsonRedisSerializer jsonSeria = new FastJsonRedisSerializer();
//包装成SerializationPair类型
RedisSerializationContext.SerializationPair serializationPair = RedisSerializationContext.SerializationPair.fromSerializer(jsonSeria);
//redis默认配置文件,并且设置过期时间
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1));
//设置序列化器
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(serializationPair);
//RedisCacheManager 生成器创建
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration);
return builder.build();
}