哪一个是Java序列化的最佳select?
我目前正在做一个项目,需要坚持任何一种对象(其中的实现我们没有任何控制),所以这些对象可以在之后恢复。
我们不能实现一个ORM,因为我们不能在开发时限制我们的库的用户。
我们的第一个select是使用Java默认序列化对其进行序列化,但是当用户开始传递同一对象的不同版本(属性更改types,名称…)时,我们遇到了很多恢复对象的问题。
我们尝试过使用XMLEncoder类(将对象转换为XML),但是我们发现缺lessfunction(例如不支持Enums)。
最后,我们也尝试了JAXB,但是这迫使我们的用户注释他们的类。
任何好的select?
要做的最简单的事情还是使用序列化,海事组织,但更多的思考到类的序列化forms(你真的应该这样做)。 例如:
- 显式定义SerialUID。
- 在适当的地方定义自己的序列化表单。
序列化的forms是类API的一部分,应该仔细考虑它的devise。
我不会介绍很多细节,因为我所说的几乎所有的东西都来自Effective Java。 相反,我会转介你,特别是关于序列化的章节。 它会警告您所遇到的所有问题,并为此问题提供适当的解决scheme:
http://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683
有了这个说法,如果你还在考虑一个非序列化的方法,这里有一对夫妇:
XML编组
正如许多人指出的是一个选项,但我认为你仍然会遇到向后兼容的同样的问题。 但是,使用XML编组,你会希望马上得到这些,因为一些框架可能会在初始化时为你做一些检查。
转换到/从YAML
这是一个想法,但我真的很喜欢YAML格式(至less作为一个自定义的toString()格式)。 但是真的,唯一的区别是你将会编组到YAML而不是XML。 唯一的好处是,YAML比XML更容易被人读取。 同样的限制适用。
现在是2011年,在商业级REST Web服务项目中,我们使用以下序列化程序为客户提供各种媒体types:
- XStream (用于XML但不适用于JSON)
- jackson (JSON)
- Kryo (快速,紧凑的二进制序列化格式)
- 微笑 (Jackson 1.6及更高版本的二进制格式)。
- Java对象序列化。
我们最近尝试了其他的序列化器:
- SimpleXML看起来很扎实,运行速度是XStream的两倍,但是对于我们的情况需要太多的configuration。
- YamlBeans有一些bug。
- SnakeYAML有一个与date有关的小错误。
Jackson JSON,Kryo和Jackson Smile的速度都比老版本的Java对象序列化速度快了大约3倍到4.5倍。 XStream是慢的一面。 但是这些都是坚实的select。 我们会继续监测其他三个。
其中的实施我们没有任何控制
解决办法是不要这样做 。 如果你不能控制某个types的实现,那么你不应该对它进行序列化。 故事结局。 Java序列化提供serialVersionUID专门用于pipe理不同版本的types之间的序列化不兼容性。 如果您不控制实现,则无法确定在开发人员更改某个类时是否正确更改了ID。
以“点”为例。 它可以用笛卡儿坐标系或极坐标系表示。 build立一个能够dynamic纠正这种错误的系统是非常值得的,因为它必须是devise序列化的类的开发者。
总之,这是你的devise是错的 – 不是技术。
谷歌提出了一个二进制协议 – http://code.google.com/apis/protocolbuffers/速度更快,比XML有更小的有效载荷; – 其他人build议作为备用。
协议缓冲区的优点之一是可以与C,C ++,Python和Java交换信息。
尝试使用Gson序列化为json例如。
另外一个非常快速的JDK序列化插入replace: http : //ruedigermoeller.github.io/fast-serialization/
如果序列化速度对您很重要,那么这里有一个JVM序列化器的综合基准:
就个人而言,我使用Fame很多,因为它具有与Smalltalk(大众和Squeak)和Python的互操作性。 (免责声明,我是Fame项目的主要贡献者。)
可能Castor ?
Betwixt是一个很好的用于序列化对象的库 – 但它不会是一个自动types的东西。 如果你需要序列化的对象的数量是相对固定的,这对你来说可能是一个很好的select,但是如果你的“客户”会一直在向你抛出新的类,那可能比它的价值更大尽pipe如此,比XMLEncoder更容易)。
另一种方法是要求你的客户为他们扔给你的任何物品提供适当的.betwixt文件(这有效地将责任分配给他们)。
长短序列化是艰难的 – 没有完全脑死亡的方法。 Java序列化与我所见过的大脑死亡解决scheme非常接近,但正如您发现的那样,错误地使用版本uid值可能会破坏它。 Java序列化也需要使用标记“可序列化”的界面,所以如果你无法控制你的源代码,那么你就不幸运了。
如果需求确实如你所描述的那样繁重,则可能需要对对象/方面/任何方面进行某种BCE(字节代码修改)。 这是一个小开发项目的领域之外,进入hibernate,卡斯帕尔或ORM ….
另一个想法:使用caching。 caching提供了更好的控制,可扩展性和鲁棒性的应用程序。 尽pipe如此,仍然需要序列化,但是在caching服务框架内pipe理变得更加容易。 caching可以保存在内存,磁盘,数据库或者数组中 – 或者所有的选项 – 一个溢出,等待,另一个故障转移。 Commons JCS和Ehcache是两个java实现,后者是一个免费提供高达32 GB存储的企业解决scheme(免责声明:我不为ehcache工作;-))。