1. 程式人生 > >Spring整合Redis報ClassCastException

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>