52

我目前正在开发一个项目,该项目需要保留任何类型的对象(我们无法控制其实现),以便之后可以恢复这些对象。

我们无法实现 ORM,因为我们无法在开发时限制库的用户。

我们的第一个替代方案是使用 Java 默认序列化对其进行序列化,但是当用户开始传递同一对象的不同版本(属性更改类型、名称等)时,我们在恢复对象时遇到了很多麻烦。

我们尝试过使用 XMLEncoder 类(将对象转换为 XML),但我们发现缺少功能(例如不支持 Enums)。

最后,我们还尝试了 JAXB,但这迫使我们的用户注释他们的类。

有什么好的选择吗?

4

13 回答 13

45

现在是 2011 年,在商业级 REST Web 服务项目中,我们使用以下序列化程序为客户提供各种媒体类型:

  • XStream(适用于 XML,但不适用于 JSON)
  • 杰克逊(用于 JSON)
  • Kryo(一种快速、紧凑的二进制序列化格式)
  • 微笑(Jackson 1.6 及更高版本附带的二进制格式)。
  • Java 对象序列化。

我们最近尝试了其他序列化程序:

  • SimpleXML看起来很可靠,运行速度是 XStream 的 2 倍,但在我们的情况下需要太多配置。
  • YamlBeans有几个错误。
  • SnakeYAML有一个与日期相关的小错误。

Jackson JSON、Kryo 和 Jackson Smile 都比旧的 Java 对象序列化快得多,大约快 3 到 4.5 倍。XStream 速度较慢。但在这一点上,这些都是可靠的选择。我们将继续监视其他三个。

于 2011-03-14T02:46:20.870 回答
20

http://x-stream.github.io/不错,请看一下!很方便

于 2008-10-27T07:43:35.367 回答
16

我们无法控制哪些实现

解决方案是不要这样做。如果您无法控制类型的实现,则不应将其序列化。故事结局。Java 序列化提供了专门用于管理类型不同版本之间的序列化不兼容性的 serialVersionUID。如果您不控制实现,则无法确保在开发人员更改类时正确更改了 ID。

举一个“点”的简单例子。它可以用笛卡尔坐标系或极坐标系来表示。构建一个可以动态处理这些修正的系统的成本太高了——它确实必须是设计序列化的类的开发人员。

简而言之,错的是你的设计——而不是技术。

于 2008-10-27T12:39:10.993 回答
13

对你来说最简单的事情仍然是使用序列化,IMO,但更多地考虑类的序列化形式(无论如何你真的应该这样做)。例如:

  1. 显式定义 SerialUID。
  2. 在适当的地方定义您自己的序列化表单。

序列化形式是类 API 的一部分,在其设计中应仔细考虑。

我不会详细介绍,因为我所说的几乎所有内容都来自 Effective Java。相反,我将向您推荐它,特别是有关序列化的章节。它会警告您遇到的所有问题,并为问题提供适当的解决方案:

http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683


话虽如此,如果您仍在考虑非序列化方法,这里有几个:

XML 编组

正如许多人指出的那样,这是一种选择,但我认为您仍然会遇到向后兼容性的相同问题。但是,通过 XML 编组,您有望立即捕捉到这些,因为某些框架可能会在初始化期间为您做一些检查。

与 YAML 的转换

这是我一直在玩弄的一个想法,但我真的很喜欢 YAML 格式(至少作为自定义的 toString() 格式)。但实际上,对您而言,唯一的区别是您将编组为 YAML 而不是 XML。唯一的好处是 YAML 比 XML 更易于阅读。同样的限制适用。

于 2008-10-27T12:23:13.867 回答
11

google 提出了一种二进制协议——http: //code.google.com/apis/protocolbuffers/速度更快,与 XML 相比具有更小的有效负载——其他人建议将其作为替代协议。

协议缓冲区的优点之一是它可以与 C、C++、python 和 java 交换信息。

于 2008-10-28T02:46:35.153 回答
5

例如,尝试使用Gson序列化为 json 。

于 2008-10-27T07:45:54.347 回答
5

也是一个非常快速的 JDK 序列化插件替换: http ://ruedigermoeller.github.io/fast-serialization/

于 2012-12-06T22:23:54.233 回答
4

如果序列化速度对您很重要,那么这里有一个 JVM 序列化程序的综合基准:

于 2013-07-16T11:53:31.973 回答
1

可能是蓖麻

于 2008-10-27T11:15:37.310 回答
1

就个人而言,我经常使用Fame,因为它具有与 Smalltalk(大众和 Squeak)和 Python 的互操作性。(免责声明,我是 Fame 项目的主要贡献者。)

于 2008-10-27T12:39:23.240 回答
1

Betwixt是一个很好的序列化对象库——但它不会是一种自动的东西。如果您必须序列化的对象数量相对固定,这对您来说可能是一个不错的选择,但如果您的“客户”一直向您抛出新类,则可能会付出更多的努力而不值得(但是,对于所有特殊情况,绝对比 XMLEncoder 更容易)。

另一种方法是要求您的客户为他们扔给您的任何对象提供适当的 .betwixt 文件(这有效地减轻了他们的责任)。

长短 - 序列化很难- 没有完全脑死的方法。Java 序列化是我所见过的最接近脑死的解决方案,但正如您所发现的,不正确地使用版本 uid 值可能会破坏它。Java 序列化还需要使用标记“Serializable”接口,所以如果你不能控制你的源代码,那你就有点不走运了。

如果要求确实如您所描述的那样艰巨,您可能不得不对对象/方面/任何东西诉诸某种 BCE(字节码修改)。这已经超出了一个小型开发项目的领域,进入了 Hibernate、Casper 或 ORM 的领域......

于 2008-10-28T02:34:14.647 回答
0

SBE 是一个成熟的库,用于快速、基于字节缓冲区的序列化库,并且能够进行版本控制。但是,它有点难以使用,因为您需要在其上编写长度包装类。

鉴于它的缺点,我最近做了一个受 SBE 和 FIX 协议(交换交易/报价消息的通用金融市场协议)启发的纯 Java 序列化库,它试图在克服它们的弱点的同时保持两者的优点。你可以看看https://github.com/iceberglet/anymsg

于 2019-04-13T08:42:28.033 回答
-1

另一个想法:使用缓存。缓存为应用程序提供了更好的控制、可扩展性和健壮性。尽管如此,仍然需要序列化,但是在缓存服务框架内管理变得更加容易。缓存可以保存在内存、磁盘、数据库或阵列中——或所有选项中——其中一个是溢出、备用、故障转移。Commons JCS 和 Ehcache 是两个 java 实现,后者是一个企业解决方案,最多可释放 32 GB 的存储空间(免责声明:我不为 ehcache 工作;-))。

于 2013-08-10T21:57:06.923 回答