一、问题描述
问题描述:
前提:向Redis
中SET
值的是一个JFinal项目,使用的Jedis客户端API操作的,把一个对象转成byte[]
形式存入Redis中。
然后在另一个SpringBoot项目中我通过Spring自带的RedisTemplate
对象来获取,一直失败。
接下来就是我的踩坑记录:
二、踩坑记录
使用StringRedisTemplate获取值(即采用StringRedisSerializer序列化方式)
然后我使用命令行获取去发现返回同样是乱码:
又换成Jackson2JsonRedisSerializer进行反序列化,还是报错,JSON反序列化失败:
使用FastJson反序列化也还是失败:
使用默认的序列化方式,还是失败:
三、黎明前夕
因为Redis中存储的值是字节数组,所以使用的就是默认的Jdk序列化方式。
现在重要的就是怎么反序列化的?
解铃还须系铃人
要想反序列化成功,就必须知道序列化是什么形式,
分析源码:从Jfinal项目入手,查看了Jedis客户端的set和get方法API,发现了使用的序列化方式是:FstSerializer
在set和get方法中使用了valueFromBytes和valueToBytes两个方法:
即:
valueToBytes
方法:将对象序列化为一个字节数组。
valueFromBytes
方法:将字节数组反序列化为原来的对象。
在继续深入源码发现使用的序列化和反序列化方式为 FstSerializer
:
在研究get方法的反序列化过程:
核心代码即:
FSTObjectInput fstInput = null;
try {
fstInput = new FSTObjectInput(new ByteArrayInputStream(bytes));
return fstInput.readObject();
}
所以我们就知道了序列化方式和反序列化的方法!
从Maven仓库中找到这个依赖:
<!-- https://mvnrepository.com/artifact/de.ruedigermoeller/fst -->
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.57</version>
</dependency>
然后从Redis中取出字节数组,在按照反序列化方法还原出原来对象:
//定义get方法,返回字节数组形式的Value
public byte[] get(byte[] key) {
return (byte[]) redisTemplate.execute((RedisCallback<byte[]>) redisConnection -> {
// 传入byte[]类型的key,获取byte[]类型的value
byte[] bytes = redisConnection.get(key);
return bytes;
});
}
然后进行反序列化:
byte[] bytes = get(redisKey.getBytes());
FSTObjectInput fstInput = new FSTObjectInput(new ByteArrayInputStream(bytes));;
SiBean redisSi = (SiBean)fstInput.readObject();
然后到此一位就大功告成了,但是又出现了最后一个Bug!!
报错信息提示没有找到这个Class。由于在向Redis中存值的时候直接是一个对象转字节数组,所以字节数组中包含对象的完整类名信息,所以我们还需要再相同的包路径下创建对应的对象,还有一点需要注意:这个对象需要实现Jdk的序列化接口:
四、成功解决
解决方法:
- 使用
JdkSerializationRedisSerializer
序列化方式接收字节数组。 - 使用
FSTObjectInput
对象将字节数组反序列化。 - 对象
全类名要保持一致
,并且实现序列化接口
。