java常用序列化解析
认识序列化
序列化 对于每一个程序员都算是再熟悉不过的名词了,但是对于市面是各种流行的序列化方式又是否真正了解并能找出一个最适合的序列化方式呢!
概念
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
理解
按上述描述的话 简单的理解就是某一天你对象惹你生气了,怎么办!忍,是不可能了,那就把他给序列化一下 1.选个规则 比如编个号 2.拿起指甲刀 按照编号大卸八十八块。但是当你气消了 怎么办? 一堆脂肪可不会说话,反序列化不就行了 真傻,幸好之前有编号 按照编号再组装到一起 完活。 简单吧 有对象的小朋友可以尝试下!
引玉
估计大家也都清楚了什么是序列化和反序列化接下来就给大家浅析下java 常用的几种序列化方式: JDK自带序列化、JSON序列化、Protostuff序列化 的使用以及实现原理。
JDK序列化
创建要序列化的实体
正反序列化实现
此时会发现JDK自带的序列化在使用上很简单直接通过 ObjectOutputStream 的 writeObject() 方法将 person 对象写入到了一个byte数组里 而反序列化的时候再通过 ObjectInputStream() 的 readObject() 转成对象 并且强转成 Person 的对象 那么就引申出一个猜想: 是不是在序列化时将对象的所有内容信息都进行了存储!
验证猜想之前先给大家看下结果吧!
接着小编一顿源码分析 找到这段代码
结论
JDK自带的序列化方式稳定性很高因为他将所有的内容都涵盖在序列化后的数组对象里但是因此也会导致一个问题 就是占用了过多的空间去存储并不需要的那些东西,这也是我们对JDK序列化避而远之的原因之一。那Json序列化又会有什么优化吗
JSON序列化
用例
结果
结果证明json序列化的结果不到jdk序列化的一半,说到这儿聪明的小伙伴都已经为什么了 是的看下这张图你就知道了
就是因为json格式的数据只保留了key-value 而其他的无关属性都没保存,所以在反序列化的时候需要使用类来做一个反转的依据,这里就不过多的做说明了!
protostuff 序列化
protostuff是基于protobuff的一种序列化方式,相较于protobuf它更简单不需要再手动创建.proto文件等过程! 使用protostuff首先我们需要引入相关的依赖
<pre class="prettyprint hljs xml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; word-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.5.3</version>
</dependency></pre>
DEMO
下面我们来分析下protostuff的序列化过程
首先引入一个 schema 的概念
<pre class="prettyprint hljs xquery" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; word-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">官方的解释是
schema是:
对象的序列化逻辑
一个对象的反序列化逻辑
对对象所需字段的验证
对象的字段名到字段号的映射
对象的实例化。</pre>
个人的理解: 基于类本身所提炼出来的正反序列化所需的所有关键信息!用于正反序列化的验证及实例化
实现过程
在序列化的时候会根据类型的不同调用RuntimeUnsafeFieldFactory类下相应匿名类的writeto()方法进行序列化,序列化的时候首先会 在类 ProtostuffOutput 下makeTag
我们可以看出这个Tag包含了 fieldNumber 和 WIRETYPE_VARINT 前面的fieldNum代表的是成员变量的序号 后面的WIRETYPE代表的是序列化类型由此我们大概可以了解到protostuff的一些玄机 json用的是变量名 而protostuff用的是变量序号以及类型做标识!
猜想
1.protostuff序列化和变量的名字无关!
2.从后面增加减少变量不影响反序列化!
3.当序列化的变量属性变化了是不是序列化失败!
这时我们翻出之前DEMO的运行结果
通过结果我们可以看出Dog的实体能正常反序列化出Person的实体而Cat的实体却报出异常,同时Dog增加的变量为null,所以上面的猜想是成立的,同时发现序列化以后的byte数组是最小的也符合预期
最后声明 本文只是从宏观方面对各种序列化进行分析介绍,并未深入到各序列化底层对不同数据类型的值转成byte[]的具体实现 在底层方面protostuff也是有所优化的有了这些了解相信大家一定会更好的评估自己的需求选择适合自己的序列化方式。