Redis缓存序列化问题

RedisSerializer

RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer

SpringBoot提供的Redis存储序列化方式,常用的有以下几种:

  • JdkSerializationRedisSerializer:将数据序列化为对象;
  • StringRedisSerializer:将数据序列化为字符串;
  • Jackson2JsonRedisSerializer、GenericJackson2JsonRedisSerializer:将数据序列化为json;

JdkSerializationRedisSerializer: 使用JDK提供的序列化功能。
优点是反序列化时不需要提供类型信息(class);
缺点是需要实现Serializable接口,还有序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。

Jackson2JsonRedisSerializer: 使用Jackson库将对象序列化为JSON字符串。
优点是速度快,序列化后的字符串短小精悍,不需要实现Serializable接口。缺点也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。

RedisConfig

KeyGenerator

默认使用SimpleKeyGenerator

public class SimpleKeyGenerator implements KeyGenerator {
  //...
    public Object generate(Object target, Method method, Object... params) {
        return generateKey(params);
    }
    public static Object generateKey(Object... params) {
        if (params.length == 0) {
            return SimpleKey.EMPTY;
        } else {
        //...
           return new SimpleKey(params);
        }
    }
}
public class SimpleKey implements Serializable {
    public static final SimpleKey EMPTY = new SimpleKey(new Object[0]);
    private final Object[] params;
    private transient int hashCode;
    //...
    public String toString() {
        return this.getClass().getSimpleName() + " [" + StringUtils.arrayToCommaDelimitedString(this.params) + "]";
    }
}

从上述代码可见,会将参数params通过SimpleKey组装,生成一长串字符串(类名+[params…])
一般可覆写如下:

import org.apache.commons.codec.digest.DigestUtils;

 @Bean
 @Override
 public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            Map<String, Object> container = new HashMap<>(4);
            Class<?> targetClassClass = target.getClass();
            // 类地址
            container.put("class", targetClassClass.toGenericString());
            // 方法名称
            container.put("methodName", method.getName());
            // 包名称
            container.put("package", targetClassClass.getPackage());
            // 参数列表
            for (int i = 0; i < params.length; i++) {
                container.put(String.valueOf(i), params[i]);
            }
            // 转为JSON字符串
            String jsonString = ObjectMapperUtil.obj2String(container);
            // 做SHA256 Hash计算,得到一个SHA256摘要作为Key
            return DigestUtils.sha256Hex(jsonString);
        };
    }

ValueSerializer

问题:
从redis取数据将json反序列化为具体pojo时,报错java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.XXX
解决:
在ObjectMapper添加一行
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

原先使用的方法enableDefaultTyping已经过期,有安全漏洞Jackson-databind

    @SuppressWarnings("all")
    @Bean(name = "redisTemplate")
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        // 使用Jackson2JsonRedisSerialize替换默认序列化方式
        Jackson2JsonRedisSerializer<?> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        jackson2JsonRedisSerializer.setObjectMapper(ObjectMapperUtil.objectMapper);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

SimpleGrantedAuthority

问题:
Cannot construct instance of 'org.springframework.security.core. authority.SimpleGrantedAuthority'
解决:
在ObjectMapper 添加一行objectMapper.addMixIn(SimpleGrantedAuthority.class,SimpleGrantedAuthorityMixin.class);

详细请看:
实体类字段为接口的json序列化报错的解决方法 以 SpringSecurity UserDetails实现类 GrantedAuthority 为例

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot中配置Redis序列化方式需要进行以下步骤: 1. 创建一个RedisCacheConfig类,并使用@Configuration注解标记该类为配置类。 2. 在RedisCacheConfig类中创建一个@Bean方法,返回一个CacheManager对象。在该方法中,创建一个RedisCacheManager对象,并将其作为参数传递给redisTemplate方法。 3. 在RedisCacheConfig类中创建另一个@Bean方法,返回一个RedisTemplate对象。在该方法中,首先创建一个RedisTemplate对象,并将其连接工厂作为参数传递给setConnectionFactory方法。然后,创建一个StringRedisSerializer对象,并分别调用setKeySerializer、setValueSerializer、setHashKeySerializer和setHashValueSerializer方法将其设置为RedisTemplate的序列化器。 4. 最后,在你的SpringBoot应用程序中引入RedisCacheConfig类,以便使用配置的Redis序列化方式进行缓存操作。 这样配置后,SpringBoot应用程序在将数据存储到Redis时,会使用Fastjson进行序列化和反序列化操作,确保数据的正确性和可读性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot Redis配置Fastjson进行序列化和反序列化实现](https://download.csdn.net/download/weixin_38528463/12933432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [springboot集成redis序列化配置](https://blog.csdn.net/pingchangmile/article/details/112529583)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值