java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > RedisTemplate 反序列泛型丢失

Spring的RedisTemplate的json反序列泛型丢失问题解决

作者:村姑飞来了

本文主要介绍了Spring RedisTemplate中使用JSON序列化时泛型信息丢失的问题及其提出三种解决方案,可以根据性能需求选择方案,下面就来具体了解一下

背景

在使用redisTemplate操作redis时我们针对对象的序列化通常将序列化成json存储到redis。一般如下配置

@Bean  
@ConditionalOnMissingBean  
public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory redisConnectionFactory,  
                                         ObjectProvider<RedisTemplateCustomizer> customizers) {  
    RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();  
    redisTemplate.setConnectionFactory(redisConnectionFactory);  
  
    StringRedisSerializer keySerializer = new StringRedisSerializer();  
    redisTemplate.setKeySerializer(keySerializer);  
    redisTemplate.setHashKeySerializer(keySerializer);  
  
    ObjectMapper objectMapper = ObjectMapperWrapper.getObjectMapper();  
    GenericJackson2JsonRedisSerializer valueSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);  
    redisTemplate.setValueSerializer(valueSerializer);  
    redisTemplate.setHashValueSerializer(valueSerializer);  
  
    customizers.orderedStream().forEach((customizer) -> customizer.customize(redisTemplate));  
    return redisTemplate;  
}

使用GenericJackson2JsonRedisSerializer进行配置。但是这种方式会引发一个问题当进行反序列时如果是对象则会报错例如: SecurityUserInfo o = (SecurityUserInfo) redisTemplateObject.opsForValue().get(key); 会报linkedHashMap无法转成具体的类型。因为序列化的json没有包含类型信息。只能按照默认的方式转换成linkedHashMap

解决方案

方案一

将jackson库的ObjectMapper序列化时带上类型信息mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); 但是这种方式会有几个缺点:

方案二

不使用activateDefaultTyping,查询的时候使用Object接收,然后使用mapper.convertValue方法转换。缺点是多一次序列化的操作,影响性能

方案三

曲线救国,使用ScopeValue将类型信息传递给RedisTemplate的序列化器(也可以用ThreadLocal),当反序列化时动态获取其类型。这个方式需要增加几个类,使用方式变化一下

import lombok.extern.slf4j.Slf4j;  
  
import java.util.concurrent.Callable;  
  
/**  
 * @author wxl  
 */@Slf4j  
@SuppressWarnings("all")  
public class RedisDeserializeHelper {  
  
    public static final ScopedValue<Class<?>> TYPE = ScopedValue.newInstance();  
  
    public static <R> R call(Class<R> clazz, Callable<Object> op) {  
        try {  
            Object call = ScopedValue.where(TYPE, clazz).call(op);  
            if (call == null) {  
                return null;  
            }  
            if (clazz.isAssignableFrom(call.getClass())) {  
                return (R) call;  
            }  
            return (R) call;  
        } catch (Exception e) {  
            log.error("redis deserialize failed", e);  
            throw new RuntimeException(e);  
        }  
    }  
  
    public static Class<?> get() {  
        return TYPE.get();  
    }  
}
import com.fasterxml.jackson.databind.ObjectMapper;  
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;  
import org.springframework.data.redis.serializer.SerializationException;  
  
/**  
 * @author wxl  
 */public class SofastGenericJackson2JsonRedisSerializer extends GenericJackson2JsonRedisSerializer {  
  
    public SofastGenericJackson2JsonRedisSerializer(ObjectMapper objectMapper) {  
        super(objectMapper);  
    }  
  
    @Override  
    public Object deserialize(byte[] source) throws SerializationException {  
        Class<?> clazz = RedisDeserializeHelper.get();  
        if (clazz != null) {  
            return deserialize(source, clazz);  
        }  
        return super.deserialize(source);  
    }  
  
    @Override  
    public <T> T deserialize(byte[] source, Class<T> type) throws SerializationException {  
        return super.deserialize(source, type);  
    }  
}
SecurityUserInfo securityUserInfo = RedisDeserializeHelper.call(SecurityUserInfo.class, () -> redisTemplateObject.opsForValue().get(key));

总结

 到此这篇关于Spring的RedisTemplate的json反序列泛型丢失问题解决的文章就介绍到这了,更多相关RedisTemplate 反序列泛型丢失内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文