java - 如何处理包改变的Java序列化对象?

标签 java serialization versioning

我有一个存储在 HttpSession 对象中的 Java 类,该对象在集群环境中的服务器之间进行序列化和传输。为了便于解释,我们称这个类为“人”。

在改进代码的过程中,此类已从“com.acme.Person”移至“com.acme.entity.Person”。在内部,该类保持完全相同(相同的字段、相同的方法、相同的一切)。

问题是我们有两套服务器同时运行旧代码和新代码。 使用旧代码的服务器已序列化 HttpSession 对象,当新代码反序列化它时,它会抛出 ClassNotFoundException,因为它找不到对 com.acme.Person 的旧引用。此时,很容易处理这个问题,因为我们可以使用新包重新创建对象。那么问题就变成了新服务器中的 HttpSession 将使用对 com.acme.entity.Person 的新引用序列化对象,而当它在运行旧代码的服务器中被反序列化时,将抛出另一个异常。此时,我们不能再处理这个异常了。

对于这种情况,应遵循的最佳策略是什么? 有没有办法告诉新服务器使用对旧包的引用序列化对象并将对旧包的引用反序列化为新包? 一旦所有服务器都运行新代码,我们将如何过渡到使用新包并忘记旧包?

最佳答案

我找到了这个 blog post声称有一个解决方案,尽管它没有非常清楚地说明。

它实际上是说,您创建了一个 ObjectInputStream 的子类,它覆盖了 readClassDescriptor 方法来执行如下操作:

@Override
protected java.io.ObjectStreamClass readClassDescriptor() 
        throws IOException, ClassNotFoundException {
    ObjectStreamClass desc = super.readClassDescriptor();
    if (desc.getName().equals("oldpkg.Widget")) {
        return ObjectStreamClass.lookup(newpkg.Widget.class);
    }
    return desc;
};

你也应该看看这个 SO question and its answers其中涵盖了与您的问题相同的一些理由。

我的建议是:不要支持旧版本软件读取新版本序列化数据的情况。

  • 这是一个鼓励(实际上是强制)人们升级到最新版本代码库的好机会。一般来说,尽早发生这种情况符合每个人的利益。

  • 如果出于其他原因强制人们升级为时过早,那么 (IMO) 您应该认真考虑退出您对类/包名称的更改。等到您有了明确的升级战略/计划,该战略/计划 1) 技术上合理,并且 2) 所有利益相关者都可以接受。

关于java - 如何处理包改变的Java序列化对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5305473/

相关文章:

java - 序列化日期 : Swagger and Spring-MVC

java - LinkedList 中的序列化如何工作?

java - Gradle中基于Git的自动版本控制

go - 处理 api 版本的惯用方法是什么

XML 版本控制算法

java - 无法用 Java 编译 MPI 程序 - UnsupportedClassVersionError

java - 小数java

java - 使用 serialVersionUID 还是禁止警告?

java - Comparable.compareTo 接口(interface)语义是什么?

java - EJB 3 JMS 配置加载异常 || 7 号