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
二、定製我們的序列化工具
我是使用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>