起因:一次需求对一个pojo类增加了新字段,并保存到了Redis中,测试没有问题,但是到生产环境却出现了反序列化失败。
1. 问题起因以及解决方案
1. 失败原因:
"Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException:
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is
java.io.InvalidClassException: com.tellme.controller.RedisController$User; local class incompatible:
stream classdesc serialVersionUID = 3688184446225449117,
local class serialVersionUID = 6846178843376749314"
在复习盘点-Java序列化方式(2)JAVA原生序列化以及Protostuff序列化中,指出反序列化不同的UID导致InvalidClassException
异常。
原始代码:
@RestController
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
//某一接口存储到Redis中
@GetMapping("redis/set")
public String set() {
User user=new User();
user.setId(100);
user.setName("tom");
//保存到Redis中
redisTemplate.opsForValue().set("b:test",user);
User o = (User)redisTemplate.opsForValue().get("b:test");
return o.toString();
}
//别的接口在获取Redis里面存储的对象
@GetMapping("redis/get")
public String get() {
User o = (User)redisTemplate.opsForValue().get("b:test");
return o.toString();
}
@Data
@ToString
public static class User implements Serializable {
private int id;
private String name;
}
}
注:Redis使用了默认的JDK的序列化方式和反序列化方式。
而一次新的需求中,User
对象加了一个字段,导致旧数据反序列化失败。
根本原因:类serialVersionUID
是自动生成的,类被修改后,生成的serialVersionUID
就会变化。旧数据使用上一个版本的serialVersionUID
存储到Redis中,而本地类的版本号为新的serialVersionUID
。故不能反序列化。
那出现这个问题,解决方案是什么呢?类需要手动声明修改前的
serialVersionUID
。
@RestController
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("redis/set")
public String set() {
User user=new User();
user.setId(100);
user.setName("tom");
//保存到Redis中
redisTemplate.opsForValue().set("b:test",user);
User o = (User)redisTemplate.opsForValue().get("b:test");
return o.toString();
}
@GetMapping("redis/get")
public String get() {
User o = (User)redisTemplate.opsForValue().get("b:test");
return o.toString();
}
@Data
@ToString
public static class User implements Serializable {
//手动声明为旧版本的序列化号
private static final long serialVersionUID = 3688184446225449117L;
private int id;
private String name;
//新加的字段
private int age;
}
}
2. 思考
使用JDK序列化时,pojo类必须声明Serializable
接口,pojo类中推荐手动声明serialVersionUID,设置为1L即可。
网友评论