石家庄做网站电话,河南网站优化公司,处理营销型网站建设策划的几个误区,codex wordpress org文章目录一、简介二、序列化框架1、JDK2、XML序列化3、JSON序列化4、Hessian5、Avro序列化6、Kyro序列化7、Protostuff三、序列化框架对比测试1、对象准备2、JDK方式3、FastJson方式4、Hessian方式5、Protostuff方式6、测试代码四、总结五、序列化应用场景六、注意事项一、简介…
文章目录一、简介二、序列化框架1、JDK2、XML序列化3、JSON序列化4、Hessian5、Avro序列化6、Kyro序列化7、Protostuff三、序列化框架对比测试1、对象准备2、JDK方式3、FastJson方式4、Hessian方式5、Protostuff方式6、测试代码四、总结五、序列化应用场景六、注意事项一、简介
序列化将Java对象转化成字节数组。
反序列化将字节数组转化成Java对象。 影响序列化选择有两个因素 序列化之后码流的大小如果太大那么将会影响网络传输的性能。 序列化和反序列化过程的性能。 二、序列化框架
1、JDK 2、XML序列化
XML 协议良好的可读性自由度极高的扩展性成了很长一段时间的序列化标准规范
可以说XML序列化是开发中最常见也是发展时间最久的协议并且支持跨进程和跨语言交互。
但是缺陷也很明显即XML规范下的每一个属性和值都是固定的标签形式导致序列化后的字节流文件很大而且解析复杂效率很低。
方案最常见的是 XStream 和 Java自带的XML序列化和反序列化 两种。 3、JSON序列化
XML序列化发展了多年后也浮现了一些问题比如开发并不简便解析XML复杂度较高还有XML的标准规范比较多自由度过高导致很难有效的指定格式校验等于是一种新的 轻量级的序列化交互的方案--JSONJavaScript Object Notation 出现了相对于XML来说json格式语法简单自由度较高有很高的可读性并且在JSON序列化后的字节流小于XML序列化的结果解析起来更方便于是基于JSON的接口成了新的标准规范之一。
方案最常见的Jackson、阿里巴巴开源的FastJson、谷歌的GSON。 4、Hessian
简单说来Hessian 是一个轻量级的RPC框架。
它基于HTTP协议传输使用Hessian二进制序列化对于数据包比较大的情况比较友好。 5、Avro序列化
Avro 序列化设计初衷是为了支持大批量数据交换的应用支持二进制序列化方式并且自身提供了动态语言支持可以更加便捷、快速处理大批量的Avro数据 6、Kyro序列化
Kyro序列化 是主流的比较成熟的序列化方案之一目前广泛使用在大数据组件中比如Hive、Storm等性能比起Hessian还要优越但是缺陷较明显不支持跨语言交互在dubbo2.6.x版本开始已经加入了Kyro序列化的支持。 7、Protostuff
Protobuf 是谷歌提出的序列化方案不同的是此方案 独立于语言、平台谷歌提供了多个语言如java、c、go、python等语言的实现也提供了多平台的库文件支持使用比较广泛优点在于 性能开销很小压缩率很高但是缺陷也很明显可读性很差并且protobuf需要使用特定语言的库进行翻译转换使用起来较为麻烦。 三、序列化框架对比测试
下面我们挑选 JDK、FastJson、Hessian、Protostuff 四种序列化方式进行对比测试。 测试之前我们需要准备序列化对象对象在序列化时需要注意以下几个关键字 Serializable接口是一个标志性接口标识可以在 JVM 中进行序列化JVM 会为该类自动生成一个序列化版本号。参与序列化与反序列化的类必须实现 Serializable 接口。 serialVersionUID类属性序列化版本号用于给 JVM 区别同名类没有提供版本号JVM会默认提供序列化版本号。 transient关键字当序列化时不希望某些属性参与则可以使用这个关键字标注该属性。 1、对象准备
SHeader.java
package com.springboottest.serialize.model;import java.io.Serializable;
import java.util.Map;public class SHeader implements Serializable {private int code;private int length;private String type;private MapString, Object attach;public int getCode() {return code;}public void setCode(int code) {this.code code;}public int getLength() {return length;}public void setLength(int length) {this.length length;}public String getType() {return type;}public void setType(String type) {this.type type;}public MapString, Object getAttach() {return attach;}public void setAttach(MapString, Object attach) {this.attach attach;}
}SRequest.java
package com.springboottest.serialize.model;import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;public class SRequest implements Serializable {private String version;private SHeader header;private Object body;public String getVersion() {return version;}public void setVersion(String version) {this.version version;}public SHeader getHeader() {return header;}public void setHeader(SHeader header) {this.header header;}public Object getBody() {return body;}public void setBody(Object body) {this.body body;}public static class SRequestBuilder{public static SRequest build(){SRequest request new SRequest();request.setVersion(1.0.0);SHeader header new SHeader();header.setCode(200);header.setLength(202);header.setType(Object);MapString, Object attach new HashMapString, Object();attach.put(name, davis);attach.put(age, 30);header.setAttach(attach);request.setHeader(header);request.setBody({\code\:200, \msg\:\success\});return request;}}
}序列化接口 AbstractSerialize.java
package com.springboottest.serialize;public abstract class AbstractSerialize {public abstract T byte[] serialize(T obj);public abstract T T deserialize(byte[] data, ClassT clazz);
}2、JDK方式
JDK自带的序列化反序列化方式需要用到的两个类 ObjectOutputStreamIO类包含序列化对象的方法writeObject() ObjectInputStreamIO类包含反序列化对象的方法readObject() 具体代码 JDKSerialize.java
package com.springboottest.serialize;import com.springboottest.serialize.model.SRequest;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class JDKSerialize extends AbstractSerialize{Overridepublic T byte[] serialize(T obj) {if (obj null){throw new NullPointerException();}ByteArrayOutputStream bos new ByteArrayOutputStream();try {ObjectOutputStream oos new ObjectOutputStream(bos);oos.writeObject(obj);return bos.toByteArray();} catch (Exception ex) {ex.printStackTrace();}return new byte[0];}Overridepublic T T deserialize(byte[] data, ClassT clazz) {ByteArrayInputStream bis new ByteArrayInputStream(data);try {ObjectInputStream ois new ObjectInputStream(bis);T obj (T)ois.readObject();return obj;} catch (Exception ex) {ex.printStackTrace();}return null;}
} 3、FastJson方式
FastJson 引入方式pom.xml
dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.56/version
/dependency具体代码 FastjsonSerialize.java
package com.springboottest.serialize;
import com.alibaba.fastjson.JSON;public class FastjsonSerialize extends AbstractSerialize{Overridepublic T byte[] serialize(T obj) {if (obj null){throw new NullPointerException();}String json JSON.toJSONString(obj);byte[] data json.getBytes();return data;}Overridepublic T T deserialize(byte[] data, ClassT clazz) {T obj JSON.parseObject(new String(data),clazz);return obj;}
}4、Hessian方式
Hessian 引入方式pom.xml
dependencygroupIdcom.caucho/groupIdartifactIdhessian/artifactIdversion4.0.60/version
/dependency具体代码 HessianSerialize.java
package com.springboottest.serialize;import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;public class HessianSerialize extends AbstractSerialize{Overridepublic T byte[] serialize(T obj) {if (obj null){throw new NullPointerException();}try{ByteArrayOutputStream bos new ByteArrayOutputStream();HessianOutput ho new HessianOutput(bos);ho.writeObject(obj);return bos.toByteArray();} catch(Exception ex){}return new byte[0];}Overridepublic T T deserialize(byte[] data, ClassT clazz) {if (data null){throw new NullPointerException();}try{ByteArrayInputStream bis new ByteArrayInputStream(data);HessianInput hi new HessianInput(bis);return (T)hi.readObject();} catch(Exception ex){ex.printStackTrace();}return null;}
}5、Protostuff方式
Protostuff 引入方式pom.xml
dependencygroupIdio.protostuff/groupIdartifactIdprotostuff-core/artifactIdversion1.6.0/versionscopecompile/scope
/dependencydependencygroupIdio.protostuff/groupIdartifactIdprotostuff-runtime/artifactIdversion1.6.0/version
/dependency具体代码 ProtostuffSerialize.java
package com.springboottest.serialize;import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class ProtostuffSerialize extends AbstractSerialize{/*** 避免每次序列化都重新申请Buffer空间*/private static LinkedBuffer buffer LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);/*** 缓存Schema*/private static MapClass?, Schema? schemaCache new ConcurrentHashMapClass?, Schema?();Overridepublic T byte[] serialize(T obj) {if (obj null){throw new NullPointerException();}ClassT clazz (ClassT) obj.getClass();SchemaT schema getSchema(clazz);byte[] data;try {data ProtostuffIOUtil.toByteArray(obj, schema, buffer);} finally {buffer.clear();}return data;}Overridepublic T T deserialize(byte[] data, ClassT clazz) {SchemaT schema getSchema(clazz);T obj schema.newMessage();ProtostuffIOUtil.mergeFrom(data, obj, schema);return obj;}private static T SchemaT getSchema(ClassT clazz) {SchemaT schema (SchemaT) schemaCache.get(clazz);if (schema null) {//这个schema通过RuntimeSchema进行懒创建并缓存//所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的schema RuntimeSchema.getSchema(clazz);if (schema ! null) {schemaCache.put(clazz, schema);}}return schema;}
}6、测试代码
SerializeTest.java
package com.springboottest.serialize;import com.springboottest.serialize.model.SRequest;public class SerializeTest {public static void main(String[] args) {System.out.println(------------ JDK Serialize ------------);test(new JDKSerialize());System.out.println();System.out.println(------------ FastJson Serialize ------------);test(new FastjsonSerialize());System.out.println();System.out.println(------------ Hessian Serialize ------------);test(new HessianSerialize());System.out.println();System.out.println(------------ Protostuff Serialize ------------);test(new ProtostuffSerialize());System.out.println();}public static void test(AbstractSerialize abstractSerialize){for(int i0;i5;i){testSerialize(abstractSerialize);System.out.println(----------------------);}}public static void testSerialize(AbstractSerialize abstractSerialize){AbstractSerialize serialize abstractSerialize;SRequest request SRequest.SRequestBuilder.build();SRequest result null;byte[] bytes serialize.serialize(request);System.out.println(字节长度 bytes.length);int count 100;long seriDuration 0, deseriDuration 0;long start 0, end 0;for(int i0;icount;i){start System.nanoTime();bytes serialize.serialize(request);end System.nanoTime();seriDuration (end - start);start System.nanoTime();result serialize.deserialize(bytes, SRequest.class);end System.nanoTime();deseriDuration (end - start);}System.out.println(总次数 count);System.out.println(序列化总耗时 seriDuration/1000 us);System.out.println(反序列化总耗时 deseriDuration/1000 us);System.out.println(总耗时 (seriDuration deseriDuration)/1000 us);}
}输出结果序列化和反序列化100次
------------ JDK Serialize ------------
字节长度526
总次数100
序列化总耗时10616us
反序列化总耗时73580us
总耗时84197us
----------------------
字节长度526
总次数100
序列化总耗时5269us
反序列化总耗时18589us
总耗时23859us
----------------------
字节长度526
总次数100
序列化总耗时3492us
反序列化总耗时12892us
总耗时16385us
----------------------
字节长度526
总次数100
序列化总耗时3483us
反序列化总耗时9978us
总耗时13462us
----------------------
字节长度526
总次数100
序列化总耗时2414us
反序列化总耗时9121us
总耗时11535us
---------------------------------- FastJson Serialize ------------
字节长度150
总次数100
序列化总耗时7581us
反序列化总耗时42988us
总耗时50570us
----------------------
字节长度150
总次数100
序列化总耗时8240us
反序列化总耗时10351us
总耗时18592us
----------------------
字节长度150
总次数100
序列化总耗时7231us
反序列化总耗时9794us
总耗时17026us
----------------------
字节长度150
总次数100
序列化总耗时5001us
反序列化总耗时6936us
总耗时11938us
----------------------
字节长度150
总次数100
序列化总耗时3552us
反序列化总耗时5458us
总耗时9011us
---------------------------------- Hessian Serialize ------------
字节长度243
总次数100
序列化总耗时14385us
反序列化总耗时30783us
总耗时45168us
----------------------
字节长度243
总次数100
序列化总耗时9114us
反序列化总耗时13857us
总耗时22972us
----------------------
字节长度243
总次数100
序列化总耗时7527us
反序列化总耗时12365us
总耗时19892us
----------------------
字节长度243
总次数100
序列化总耗时5211us
反序列化总耗时9830us
总耗时15042us
----------------------
字节长度243
总次数100
序列化总耗时6858us
反序列化总耗时10122us
总耗时16981us
---------------------------------- Protostuff Serialize ------------
字节长度86
总次数100
序列化总耗时2404us
反序列化总耗时5213us
总耗时7617us
----------------------
字节长度86
总次数100
序列化总耗时1450us
反序列化总耗时1668us
总耗时3119us
----------------------
字节长度86
总次数100
序列化总耗时1183us
反序列化总耗时1440us
总耗时2624us
----------------------
字节长度86
总次数100
序列化总耗时1038us
反序列化总耗时1316us
总耗时2355us
----------------------
字节长度86
总次数100
序列化总耗时991us
反序列化总耗时1509us
总耗时2501us
----------------------四、总结
序列化方式字节流大小B100次耗时us1000次耗时us10000次耗时usJDK52611 ~ 2365 ~ 78215 ~ 385FastJson1509 ~ 1811 ~ 4620 ~ 40Hessian24315 ~ 2345 ~ 63241 ~ 355Protostuff862 ~ 74 ~ 1011 ~ 20
注
字节流大小单位B字节序列化和反序列化总耗时单位us微秒
从图表中可以看出 JDK方式的码流最大不利于网络传输 从整体来看Prorostuff的码流最小序列化性能最好。 五、序列化应用场景 序列化会将内存中对象的状态转换成二进制文件保存到磁盘当中当再次使用时会从磁盘中读取该二进制文件将 Java 对象的状态恢复到内存中。 当你想把内存中的对象保存到磁盘文件或数据库中时可以使用序列化。 当你想在网络传输中传送 Java 对象时可以使用序列化。 当你想通过 RMI 传输对象时可以使用序列化。 六、注意事项 序列化只会保存对象的属性状态不会保存对象中的方法。 父类实现了 Serializable接口则其子类也自动实例化了该接口也就是说子类不用显式实现 Serializable 接口也能参与序列化和反序列化。 一个 对象 A 的实例变量引用了其他 对象 B在 A 对象实例化的过程中 也会序列化 B 前提是 A、B 两个类都实现了 Serializable 接口。 当一个类实现 Serializable 接口时最好手动指定一个序列化版本号serialVersionUID避免修改源代码后导致反序列化出现异常。 当一个类对象会被多次重复使用且一般不会对其属性做修改就可以对其进行序列化。例如数据库操作中的实体类。