目录

  1. 背景
  2. 测试
    1. 环境
    2. 工具
    3. 说明
    4. 结果
    5. 结论
  3. xstream简单教程
    1. 准备
    2. 代码 
  4. protobuf简单教程
    1. 快速入门
      1. 下载.exe编译器
      2. 编写.proto文件
      3. 利用编译器编译.proto文件生成javabean
      4. 引用jar包
      5. 直接使用javabean自带的序列化、反序列化、提取属性等方法
  5. protostuff简单教程
    1. 快速入门
      1. 引用jar包
      2. 直接使用相关序列化、反序列化语法

1、背景

  项目中http通信离不开对象的序列化和反序列化,通过序列化技术,可以夸语言实现数据的传输,例如把一个对象序列化后的二进制数据、xml格式数据存在文本文件,下次通过读取文件,然后反序列化一下即可重新生成该对象,抑或通过网络把序列化后的数据传输到另一个终端,对方通过反序列化后也可以重新复制出一个大概相同的对象出来。

  在一般项目中,xml是一个不错的选择,例如微信公众平台的大多数接口,就是使用xml技术来序列化传输的,学习成本低,可读性高,方便调试,可以直接在浏览器查看结果等等都是他的优点,对于对速度要求不高的系统来说,的确是一种不错的选择。但如果系统对序列化效率要求很高,例如想比xml快上10倍?那么可能就得考虑换成其他技术了,例如——protobuf。

  protobuf是谷歌推出的与语言无关、平台无关的通信协议,一个对象经过protobuf序列化后将变成二进制格式的数据,所以他可读性差,但换来的是占用空间小,速度快。使用protobuf要先使用特定的语法编写一个.proto文件,该文件与语言无关,然后使用特殊的编译器对该文件进行编译,生成与语言相关的文件,如java,那么将生成java的类,该类不仅有我们自己定义的属性,还提供了序列化,反序列化等其他方法。直接把该类copy到项目中,就可以使用了。不过缺点是,假如我们是数据的发送方,那么接受方也要有一个通过相同的.proto编译出来的“类”(假设对方使用java语言),才可以顺利地进行反编译。这样一来,假如我们对proto 2.6版本的编辑器对.proto文件进行编译,而对方使用的是2.3版本的编译器进行编译,那么编译出来的类是不一样的,且两个版本互不兼容。所以两方的版本要保持一致。这么一来,假如一方升级,但没及时通知另一方,那么可能导致对方无法反序列化!这个缺点也是不小的。

  针对以上缺点,一个基于protobuf的产品——protostuff诞生了,protostuff不需要依赖.proto文件,他可以直接对普通的javabean进行序列化、反序列化的操作,而效率上甚至比protobuf还快,不过使用protostuff的话可不可以xstream那样自定义转换器,这个还没研究过,如果有人研究过得,不妨留下评论。

  所以针对这三种技术,做了以下简单的比较和介绍。如果大家觉得proto系列还可以的话,或者在以后的项目中,可以考虑使用。

2、测试

2.1 测试环境

xstraem版本:1.3.1

protobuf-java版本:3.0.0-alpha-2

java版本:1.7

-Xms2048m

-Xmx2048m

2.2 测试工具

用时: 控制台输出时间

CPU&内存: jconsole

文件大小: 文件属性

2.3 说明

测试中,xml和protoBuf和protostuff三种测试所使用的JavaBean所拥有的字段类型相同、字段数量相同(约28个)、字段所附的值相同、都包含有一个List<String>字段,用List字段的size来控制JavaBean对象的大小。本次测试中size=100

2.4  结果

测试A:10000个对象

 

xstream

protobuf

protostuff

序列化

用时(ms)

2399

648

占用的CPU(%)

24.2

12.3

3.4

占用的内存(M)

154

235

每个文件大小(byte)

2822

574

574

反序列化

用时(ms)

3378

224

占用CPU(%)

15.9

14.2

6.1

占用内存(M)

248

307

备注:10000个对象

测试B:25000个对象

 

xstream

protobuf

protostuff

序列化

用时(ms)

4161

767

占用的CPU(%)

31.2

14.6

4.7

占用的内存(M)

495

228

每个文件大小(byte)

2822

574

574

反序列化

用时(ms)

6941

393

占用CPU(%)

31.9

21.9

8.1

占用内存(M)

411

382

备注:25000个对象

测试C:100000个对象

 

xstream

protobuf

protostuff

序列化

用时(ms)

12867

3070

占用的CPU(%)

42.5

44.9

22.3

占用的内存(M)

1098

1058

每个文件大小(byte)

2822

574

574

反序列化

用时(ms)

24442

4540

占用CPU(%)

38.8

68.2

24.1

占用内存(M)

2215

870

备注:50000个对象

引用最后一组数据的直方图:

2.5 结论

1、序列化:

  1.1、速度上:protostuff比protobuf快倍左右,protobuf比xml快4-5倍,该倍数随着序列化对象的增加,基本保持不变。

  1.2、CPU上:protostuff占用最少,protobuf其次,xml最后。

  1.3、内存上:protostuff占用最少,protobuf其次,xml最后。

  1.4、生成文件大小:protostuff占用最少,protobuf其次,xml最后,前面两者是后者的1/4左右。

2、反序列化

  2.1、速度上:在反序列化对象数量较少的情况下,protobuf比protostuff快1/4左右,比xml快10+倍。但随着对象数量的增加,protobuf发生了速率明显变慢的情况!从而被protostuff赶超。

  2.2、CPU上:protostuff占用最少,protobuf其次,xml最后。

  2.3、内存上:protostuff占用最少,protobuf其次,xml最后。

3、总结

  在各个方面上,protostuff的优势非常面试,而protobuf也不弱,考虑用来代替xml。

3、xstream简单教程

3.1 准备

jar包:pom.xml:

        <!-- xstream -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>

3.2 代码

1、java bean:

 package com.zjm.www.po;

 import java.util.List;

 /**
* 商品类
*/
public class Products { private String s1;
private String s2;
private String s3;
private String s4;
private String s5;
private String s6;
private String s7;
private String s8;
private String s9; private int i1;
private int i2;
private int i3;
private int i4;
private int i5;
private int i6;
private int i7;
private int i8;
private int i9; private boolean b1;
private boolean b2;
private boolean b3;
private boolean b4;
private boolean b5;
private boolean b6;
private boolean b7;
private boolean b8;
private boolean b9; private List<String> list; public String getS1() {
return s1;
} public void setS1(String s1) {
this.s1 = s1;
} public String getS2() {
return s2;
} public void setS2(String s2) {
this.s2 = s2;
} public String getS3() {
return s3;
} public void setS3(String s3) {
this.s3 = s3;
} public String getS4() {
return s4;
} public void setS4(String s4) {
this.s4 = s4;
} public String getS5() {
return s5;
} public void setS5(String s5) {
this.s5 = s5;
} public String getS6() {
return s6;
} public void setS6(String s6) {
this.s6 = s6;
} public String getS7() {
return s7;
} public void setS7(String s7) {
this.s7 = s7;
} public String getS8() {
return s8;
} public void setS8(String s8) {
this.s8 = s8;
} public String getS9() {
return s9;
} public void setS9(String s9) {
this.s9 = s9;
} public int getI1() {
return i1;
} public void setI1(int i1) {
this.i1 = i1;
} public int getI2() {
return i2;
} public void setI2(int i2) {
this.i2 = i2;
} public int getI3() {
return i3;
} public void setI3(int i3) {
this.i3 = i3;
} public int getI4() {
return i4;
} public void setI4(int i4) {
this.i4 = i4;
} public int getI5() {
return i5;
} public void setI5(int i5) {
this.i5 = i5;
} public int getI6() {
return i6;
} public void setI6(int i6) {
this.i6 = i6;
} public int getI7() {
return i7;
} public void setI7(int i7) {
this.i7 = i7;
} public int getI8() {
return i8;
} public void setI8(int i8) {
this.i8 = i8;
} public int getI9() {
return i9;
} public void setI9(int i9) {
this.i9 = i9;
} public boolean isB1() {
return b1;
} public void setB1(boolean b1) {
this.b1 = b1;
} public boolean isB2() {
return b2;
} public void setB2(boolean b2) {
this.b2 = b2;
} public boolean isB3() {
return b3;
} public void setB3(boolean b3) {
this.b3 = b3;
} public boolean isB4() {
return b4;
} public void setB4(boolean b4) {
this.b4 = b4;
} public boolean isB5() {
return b5;
} public void setB5(boolean b5) {
this.b5 = b5;
} public boolean isB6() {
return b6;
} public void setB6(boolean b6) {
this.b6 = b6;
} public boolean isB7() {
return b7;
} public void setB7(boolean b7) {
this.b7 = b7;
} public boolean isB8() {
return b8;
} public void setB8(boolean b8) {
this.b8 = b8;
} public boolean isB9() {
return b9;
} public void setB9(boolean b9) {
this.b9 = b9;
} public List<String> getList() {
return list;
} public void setList(List<String> list) {
this.list = list;
} public Products(){ } public Products(String s1, String s2, String s3, String s4, String s5,
String s6, String s7, String s8, String s9, int i1, int i2, int i3,
int i4, int i5, int i6, int i7, int i8, int i9, boolean b1,
boolean b2, boolean b3, boolean b4, boolean b5, boolean b6,
boolean b7, boolean b8, boolean b9, List<String> list) {
super();
this.s1 = s1;
this.s2 = s2;
this.s3 = s3;
this.s4 = s4;
this.s5 = s5;
this.s6 = s6;
this.s7 = s7;
this.s8 = s8;
this.s9 = s9;
this.i1 = i1;
this.i2 = i2;
this.i3 = i3;
this.i4 = i4;
this.i5 = i5;
this.i6 = i6;
this.i7 = i7;
this.i8 = i8;
this.i9 = i9;
this.b1 = b1;
this.b2 = b2;
this.b3 = b3;
this.b4 = b4;
this.b5 = b5;
this.b6 = b6;
this.b7 = b7;
this.b8 = b8;
this.b9 = b9;
this.list = list;
} @Override
public String toString() {
return "Products [s1=" + s1 + ", s2=" + s2 + ", s3=" + s3 + ", s4="
+ s4 + ", s5=" + s5 + ", s6=" + s6 + ", s7=" + s7 + ", s8="
+ s8 + ", s9=" + s9 + ", i1=" + i1 + ", i2=" + i2 + ", i3="
+ i3 + ", i4=" + i4 + ", i5=" + i5 + ", i6=" + i6 + ", i7="
+ i7 + ", i8=" + i8 + ", i9=" + i9 + ", b1=" + b1 + ", b2="
+ b2 + ", b3=" + b3 + ", b4=" + b4 + ", b5=" + b5 + ", b6="
+ b6 + ", b7=" + b7 + ", b8=" + b8 + ", b9=" + b9 + ", list="
+ list + "]";
}
}

2、序列化:

public  List<String> serializeXMLProductsList(List<Products> pList) {
if(pList == null) {
System.out.println("【XmlSerializeServiceImpl-serializeProductsListService】pList参数为空");
return null;
}
long start = System.currentTimeMillis() ;
XStream x = new XStream();
x.alias("Products", Products.class);
List<String> strList = new ArrayList<String>();
for(Products p : pList) {
String str = x.toXML(p);
strList.add(str);
}
long end = System.currentTimeMillis() ;
usedTime = end - start ;
return strList;
}

3、反序列化

    public List<Products> deserializeXMLDataListToProductsList(
List<String> xmlStrList) {
long start = System.currentTimeMillis();
List<Products> productsList = new ArrayList<Products>();
XStream xs = new XStream();
xs.alias("Products", Products.class);
for(String xmlStr : xmlStrList) {
Products p = (Products)xs.fromXML(xmlStr);
productsList.add(p);
}
long end = System.currentTimeMillis();
usedTime = end - start ;
return productsList;
}

然而,一般来说,对xstream的序列化和反序列化,要自己实现Converter接口来转化的,这样的解决一个问题,就是对方接口的字段和我们自己的javabean的字段名不一致的问题。这里不多说,可以搜索xstrem Converter,即有大量文章。

4、protobuf简单教程

4.1、快速入门:

  下载.exe编译器——编写.proto文件——利用编译器编译.proto文件生成javabean——引用jar包——直接使用javabean自带的序列化、反序列化方法

1、下载针对java的.exe编译器

protobuf编译器官方下载地址:https://developers.google.com/protocol-buffers/docs/downloads

下载不了的:点我

2、编写.proto文件

package tutorial;
option java_package = "com.zjm.www.po";
option java_outer_classname = "Products2";
message Products22 {
required string s1 = 1;
required string s2 = 2;
required string s3 = 3;
required string s4 = 4;
required string s5 = 5;
required string s6 = 6;
required string s7 = 7;
required string s8 = 8;
required string s9 = 9;
required int32 i10 = 10;
required int32 i11 = 11;
required int32 i12 = 12;
required int32 i13 = 13;
required int32 i14 = 14;
required int32 i15 = 15;
required int32 i16 = 16;
required int32 i17 = 17;
required int32 i18 = 18;
required bool b19 = 19;
required bool b20 = 20;
required bool b21 = 21;
required bool b22 = 22;
required bool b23 = 23;
required bool b24 = 24;
required bool b25 = 25;
required bool b26 = 26;
required bool b27 = 27;
repeated string list = 28;
}

其中的option java_package代表将要生成的javabean所有的包的包名

其中的option java_outer_classname代表要生成的javabean的类名

其中的message Products22可以理解为一个类似C语言的结构体,在生成的javabean中将变成一个内部类,一个.proto文件可以有无数个message

proto支持的类型与修饰符可参考该博客:http://blog.sina.com.cn/s/blog_abea023b0101dxce.html

3、利用编译器编译.proto文件生成javabean

把.proto文件放在.exe同个目录下面,打开cmd,进入同目录下,执行命令:

protoc.exe --java_out=./ test.proto

假如.proto文件没有编写错误的话,成功后在同目录下即有javabean的类生成。

4、引用jar包

jar包地址pom.xml:

        <!-- protobuf -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.0.0-alpha-2</version>
</dependency>

5、把刚刚生成的javabean复制到项目中,这里直接使用javabean自带的序列化、反序列化方法

刚刚生成的javabean为:Products2

序列化例子:

public List<byte[]> serializeProtoBufProductsList(
List<Builder> builderList) {
if(builderList == null) {
System.out.println("【ProtoBufSerializeServiceImpl-serializeProtoBufProductsService】builderList==null");
}
long start = System.currentTimeMillis();
List<byte[]> bytesList = new ArrayList<byte[]>();
for(Products2.Products22.Builder p22Builder : builderList){
Products2.Products22 p22 = p22Builder.build();
byte[] bytes = p22.toByteArray();
bytesList.add(bytes);
}
long end = System.currentTimeMillis();
usedTime = end - start ;
return bytesList;
}

builder对象由来:com.zjm.www.po.Products2.Products22.Builder,即可有生成的javabean点出来。

反序列化例子:

    public List<Products22> deserializeProtoBufDataListToProducts22List(
List<byte[]> bytesList) {
long start = System.currentTimeMillis();
List<Products22> list = new ArrayList<Products22>();
for(byte[] b : bytesList) {
try {
list.add(Products2.Products22.parseFrom(b));
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
usedTime = end - start;
return list;
}

拿出具体字段例子:

                Products22 p = Products2.Products22.parseFrom(b);
String s1 = p.getS1();
int i1 = p.getI10();
boolean b1 = p.getB19();
ProtocolStringList l = p.getListList(); for(String s : l) { }

5、protostuff简单教程

5.1 快速入门

  引用jar包——学习语法——直接使用

1、引用jar包:

pom.xml:

        <!-- protostuff -->
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.0.7</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.0.7</version>
<optional>true</optional>
<scope>provided</scope>
</dependency>

2、javabean:

同上面xml的javabean

3、序列化例子:

public List<byte[]> serializeProtoStuffProductsList(List<Products> pList) {
if(pList == null || pList.size() <= 0) {
return null;
}
long start = System.currentTimeMillis() ;
List<byte[]> bytes = new ArrayList<byte[]>();
Schema<Products> schema = RuntimeSchema.getSchema(Products.class);
LinkedBuffer buffer = LinkedBuffer.allocate(4096);
byte[] protostuff = null;
for(Products p : pList) {
try {
protostuff = ProtostuffIOUtil.toByteArray(p, schema, buffer);
bytes.add(protostuff);
} finally {
buffer.clear();
}
}
long end = System.currentTimeMillis() ;
this.userTime = end - start;
return bytes;
}

4、反序列化例子:

    public List<Products> deserializeProtoStuffDataListToProductsList(
List<byte[]> bytesList) {
if(bytesList == null || bytesList.size() <= 0) {
return null;
}
long start = System.currentTimeMillis() ;
Schema<Products> schema = RuntimeSchema.getSchema(Products.class);
List<Products> list = new ArrayList<Products>();
for(byte[] bs : bytesList) {
Products product = new Products();
ProtostuffIOUtil.mergeFrom(bs, product, schema);
list.add(product);
}
long end = System.currentTimeMillis() ;
this.userTime = end - start;
return list;
}

java序列化/反序列化之xstream、protobuf、protostuff 的比较与使用例子的更多相关文章

  1. 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化

    序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...

  2. java序列化反序列化深入探究

    When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化.写一个排序算法也用不到序列化和反序列化.但是当你想要将一个对象进行持久化写入文件,或者你想 ...

  3. java序列化反序列化深入探究(转)

    When---什么时候需要序列化和反序列化: 简单的写一个hello world程序,用不到序列化和反序列化.写一个排序算法也用不到序列化和反序列化.但是当你想要将一个对象进行持久化写入文件,或者你想 ...

  4. 初尝Java序列化/反序列化对象

    看个类: package com.wjy.bytes; import java.io.Serializable; public class ObjTest implements Serializabl ...

  5. Java序列化反序列化对象流ObjectInputStream、ObjectOutputStream

    使用Person类作为Object进行示范 注意:Object要能被写入流需要实现Serializable接口 存储的文件后缀名为.ser 示范Person类 import java.io.Seria ...

  6. Java——序列化 反序列化

    记录一下: 先粘两个比较繁琐的方法: put: public void putSerializableObject(String key, Object value, int expireTime) ...

  7. Java 序列化 反序列化 历史版本处理

    直接引用  http://www.cnblogs.com/xdp-gacl/p/3777987.html

  8. 通讯协议序列化解读(二) protostuff详解教程

    上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html  前言:上一面文章我们介绍了java序列化,以及谷歌protobu ...

  9. java protostuff 序列化反序列化工具

    protostuff是由谷歌开发的一个非常优秀的序列化反序列化工具 maven导入包: <dependency> <groupId>io.protostuff</grou ...

随机推荐

  1. [数据结构]A*寻路算法

    简易地图 如图所示简易地图, 其中绿色方块的是起点 (用 A 表示), 中间蓝色的是障碍物, 红色的方块 (用 B 表示) 是目的地. 为了可以用一个二维数组来表示地图, 我们将地图划分成一个个的小方 ...

  2. ASP.NET Core 2.0使用Log4net实现记录日志功能

    一.安装Log4net 1.使用Nuget包进行安装 在依赖项上面右键,选择“管理NuGet程序包”,如下图所示: 在浏览界面输入log4net,然后点击安装,如下图所示: 2.使用程序包管理器控制台 ...

  3. git设置HTTP代理

    git设置HTTP代理 设置HTTP代理 如果公司使用代理,git就需要设置代理才能克隆远程仓库 执行下面两条语句 git config --global http.proxy 10.167.32.1 ...

  4. 如何利用jsp实现防盗链功能

    index.jsp ----------------------------- Place your content here here is index jsp get header info a. ...

  5. 通过URI返回File文件

    /** * 通过Uri返回File文件 * 注意:通过相机的是类似content://media/external/images/media/97596 * 通过相册选择的:file:///stora ...

  6. 通过 Spark R 操作 Hive

    作为数据工程师,我日常用的主力语言是R,HiveQL,Java与Scala.R是非常适合做数据清洗的脚本语言,并且有非常好用的服务端IDE——RStudio Server:而用户日志主要储存在hive ...

  7. 【3】JVM-OutOfMemory异常重现

    JVM中常见的OOM,那么如何通过自己编写代码产生这些OOM异常呢?通过写代码重现异常,是为了避免在工作中写出有OOM BUG的代码.之前虽然看过相关文章,但是没自己写过这些代码,这次在编写的实际过程 ...

  8. discuz 模板中如何使用方法和语言标签?

    第一个问题:如何调用方法? 关于模板中eval的使用{eval php 语句}比如:<!--{eval echo "Hello World!"}--> 工作中遇到一个小 ...

  9. Java如何删除数组中的元素?

    Java中,如何删除数组元素? 示例 以下示例显示如何从数组中删除元素. package com.yiibai; import java.util.ArrayList; public class Re ...

  10. 模式识别之knn---KNN(k-nearest neighbor algorithm)--从原理到实现

    用官方的话来说,所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居),这K个实例的多数属于某个类,就把该输入实例分类到这个类中 ...