概述
1.redis操作方式一:RedisTemplate
2.redis操作方式二:基于Spring Cache
spring中使用redis目前接触的到的有两种方式,一种是使用封装的RedisTemplate工具类;另一种是使用Spring Cache,cache实现方式选择RedisCache.两种方案中都需要对序列化方式进行设置,否则会出现二进制格式的数据(不论是Redis desktop manager工具还是redis自带客户端黑窗口打开),如果需要查看数据则会影响观感,关于序列化方式设置底层都是对RedisSerializer接口进行设置,现分别说明为何出现此问题以及如何避免.
第一种:springboot中常用的redis操作对象:RedisTemplate(StringRedisTemplate属于RedisTemplate子类,此处不做说明)
对于RedisTemplate,如果不指定默认的序列化方式,默认为JdkSerializationRedisSerializer,源码分析如下:
RedisTemplate继承RedisAccessor,RedisAccessor实现InitializingBean接口,RedisTemplate重写afterPropertiesSet,容器加载实例化后进行设置序列化方式属性信息.
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
// 忽略部分代码
private @Nullable RedisSerializer<?> defaultSerializer;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null;
@SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
// 默认序列化方式不设置则使用JdkSerializationRedisSerializer
if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
classLoader != null ? classLoader : this.getClass().getClassLoader());
}
if (enableDefaultSerializer) {
// 存储key的序列化方式不设置则使用默认序列化方式(不设置则为JdkSerializationRedisSerializer)
if (keySerializer == null) {
keySerializer = defaultSerializer;
defaultUsed = true;
}
// 存储value的序列化方式不设置则使用默认序列化方式(不设置则为JdkSerializationRedisSerializer)
if (valueSerializer == null) {
valueSerializer = defaultSerializer;
defaultUsed = true;
}
// 存储HashKey的序列化方式不设置则使用默认序列化方式(不设置则为JdkSerializationRedisSerializer)
if (hashKeySerializer == null) {
hashKeySerializer = defaultSerializer;
defaultUsed = true;
}
// 存储hashValueSerializer的序列化方式不设置则使用默认序列化方式(不设置则为JdkSerializationRedisSerializer)
if (hashValueSerializer == null) {
hashValueSerializer = defaultSerializer;
defaultUsed = true;
}
}
if (enableDefaultSerializer && defaultUsed) {
Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
}
if (scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor<>(this);
}
initialized = true;
}
// 忽略部分代码
}
RedisSerializer进行存储数据时采用的序列化方式有多种,实现类如下:
最常用的就是json序列化方式:GenericJackson2JsonRedisSerializer或Jackson2JsonRedisSerializer,所以在redis相关配置类型中修改序列化方式即可.
序列化配置修改代码:
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // 设置缓存存储对象
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // 设置缓存存储对象
redisTemplate.afterPropertiesSet();
这里贴一下完整redisTemplate配置类,如果有需要可以作为参考:
@Component
public class RedisTemplateConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 自定义的string序列化器和fastjson序列化器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 过滤未知字段
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//只序列化必要shiro字段
String [] needSerialize = {"realmPrincipals"};
objectMapper.addMixIn(SimplePrincipalCollection.class, IncludeShiroFields.class);
objectMapper.setFilters(new SimpleFilterProvider().addFilter("shiroFilter", SimpleBeanPropertyFilter.filterOutAllExcept(needSerialize)));
// 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // 设置缓存存储对象
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // 设置缓存存储对象
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
第二种使用redis方式:Spring Cache
Cache接口支持多种实现,Cache接口实现类如下:
本文对RedisCache进行说明,常用的注解有@Cacheable、@CacheEvict、@CachePut,此处仅对序列化方式进行说明.RedisCache使用需要创建RedisCacheManager,其中需要对RedisCacheConfiguration进行配置.RedisCacheConfiguration设置序列化方式需要借助SerializationPair,源码如下:
public RedisCacheConfiguration serializeValuesWith(SerializationPair<?> valueSerializationPair) {
Assert.notNull(valueSerializationPair, "ValueSerializationPair must not be null!");
return new RedisCacheConfiguration(this.ttl, this.cacheNullValues, this.usePrefix, this.keyPrefix, this.keySerializationPair, valueSerializationPair, this.conversionService);
}
SerializationPair设置序列化方式源码如下:
public interface SerializationPair<T> {
static <T> RedisSerializationContext.SerializationPair<T> fromSerializer(RedisSerializer<T> serializer) {
Assert.notNull(serializer, "RedisSerializer must not be null!");
return new RedisSerializerToSerializationPairAdapter(serializer);
}
从Redistemplate中序列化源码分析可知,RedisSerializer实现类序列化方式使用的是默认jdk.
序列化修改配置:
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(genericJackson2JsonRedisSerializer)
).entryTtl(Duration.ofSeconds(seconds));
这里贴一下RedisCacheConfig完整配置,如有需要可以作为参考:
@EnableCaching
@Configuration
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManager redisCacheManager = new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
// 默认策略,未配置的 key 会使用这个
this.getRedisCacheConfigurationWithTtl(60),
// 指定 key 策略
this.getRedisCacheConfigurationMap()
);
redisCacheManager.setTransactionAware(true);
return redisCacheManager;
}
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(16);
return redisCacheConfigurationMap;
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
// 指定使用GenericJackson2JsonRedisSerializer序列化方式
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(genericJackson2JsonRedisSerializer)
).entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}
以上为自己总结梳理,如有异议,欢迎评论区评论交流!
最后
以上就是认真小鸭子为你收集整理的springboot集成redis序列化问题汇总的全部内容,希望文章能够帮你解决springboot集成redis序列化问题汇总所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复