Spring整合Redis报ClassCastException

最近在用Spring注解方式Cacheable 整合Redis的时候,报ClassCastException 异常,我方法返回值是一个PageVo, 报不能将PageVo 不能转换成String 类型。一开始网上搜都是说SpringBoot整合方案,但我用的是Spring的方式的,后来看过几篇文章,这里记录一下

一、为什么Spring redis中缓存的对象需要实现 Serializable 序列化接口

查看RedisTemplate源码,我们可以看到,在RedisTemplate中针对不同类型的数据提供了不同的序列化方式。
默认的序列化方式为JdkSerializationRedisSerializer。而我们常用的配置为键采用StringRedisSerializer来序列化,value采用默认的JdkSerializationSerializer

JdkSerializationSerializer的源码。可以看到序列化的时候调用了serializer.convert方法。在convert方法中 调用的是 DefaultSerializer 下的serialize方法。DefaultSerializer 下的serialize方法对Object对象的序列化方式是使ObjectOutputStream 将对象写入到outputStream中的。可以看到只有支持 java.io.Serializable 序列化接口的对象才能使用ObjectOutputStream进行写入与读取。这就是为什么我们使用redis缓存对象时候需要让对象实现java.io.Serializable 序列化接口的原因。

二、定制我们的序列化工具

我是使用StringRedisSerializer做Value的序列化时,StringRedisSerializer的泛型指定的是String,传其他对象就会报类型转换错误,在使用@Cacheable注解是Value属性就只能传String进来。,所以我返回值PageVo 不是String 类型,不能序列化为String 类型放入Redis的Value中。解决方案:把这个序列化方式重写了,将泛型改成Object

/**
 * 必须重写序列化器,否则@Cacheable注解的value会报类型转换错误
 */
public class StringRedisSerializer implements RedisSerializer<Object> {
 
    private final Charset charset;
 
    private final String target = "\"";
 
    private final String replacement = "";
 
    public StringRedisSerializer() {
        this(Charset.forName("UTF8"));
    }
 
    public StringRedisSerializer(Charset charset) {
        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }
 
    @Override
    public String deserialize(byte[] bytes) {
        return (bytes == null ? null : new String(bytes, charset));
    }
 
    @Override
    public byte[] serialize(Object object) {
        String string = JSON.toJSONString(object);
        if (string == null) {
            return null;
        }
        string = string.replace(target, replacement);
        return string.getBytes(charset);
    }
}

三、自定义序列化的使用

最后如果要在Spring中使用这个序列化方法我们还需要咋redis的配置文件中注册一下

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
<!--         键序列化方式 -->
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
<!--         值序列化方式 -->
        <property name="valueSerializer">
<!--             <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> -->
<!--             <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> -->
            <bean class="com.yz.StringRedisSerializer "/>
        </property>
</bean>

猜你喜欢

转载自blog.csdn.net/yz357823669/article/details/83245739