java序列化/反序列化之xstream、protobuf、protostuff 的比較與使用例子


目錄

  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 說明

測試中,xmlprotoBuf和protostuff三種測試所使用的JavaBean所擁有的字段類型相同、字段數量相同(約28個)、字段所附的值相同、都包含有一個List<String>字段,用List字段的size來控制JavaBean對象的大小。本次測試中size=100

 

2.4  結果

測試A:10000個對象

 

 

xstream

protobuf

protostuff

序列化

用時(ms)

2399

648

261

占用的CPU(%)

24.2

12.3

3.4

占用的內存(M)

154

235

92

每個文件大小(byte

2822

574

574

 

反序列化

用時(ms)

3378

167

224

占用CPU(%)

15.9

14.2

6.1

占用內存(M)

248

307

164

備注:10000個對象

 

測試B:25000個對象

 

xstream

protobuf

protostuff

序列化

用時(ms)

4161

767

293

占用的CPU(%)

31.2

14.6

4.7

占用的內存(M)

495

228

194

每個文件大小(byte

2822

574

574

 

反序列化

用時(ms)

6941

252

393

占用CPU(%)

31.9

21.9

8.1

占用內存(M)

411

382

348

備注:25000個對象

測試C:100000個對象

 

xstream

protobuf

protostuff

序列化

用時(ms)

12867

3070

704

占用的CPU(%)

42.5

44.9

22.3

占用的內存(M)

1098

1058

572

每個文件大小(byte

2822

574

574

 

反序列化

用時(ms)

24442

4540

1522

占用CPU(%)

38.8

68.2

24.1

占用內存(M)

2215

597

870

備注:50000個對象

引用最后一組數據的直方圖:

2.5 結論

1、序列化:

  1.1、速度上:protostuff比protobuf快3倍左右,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:

  1 package com.zjm.www.po;
  2 
  3 import java.util.List;
  4 
  5 /**
  6  * 商品類
  7  */
  8 public class Products {
  9 
 10     private String s1;
 11     private String s2;
 12     private String s3;
 13     private String s4;
 14     private String s5;
 15     private String s6;
 16     private String s7;
 17     private String s8;
 18     private String s9;
 19     
 20     private int i1;
 21     private int i2;
 22     private int i3;
 23     private int i4;
 24     private int i5;
 25     private int i6;
 26     private int i7;
 27     private int i8;
 28     private int i9;
 29     
 30     private boolean  b1;
 31     private boolean  b2;
 32     private boolean  b3;
 33     private boolean  b4;
 34     private boolean  b5;
 35     private boolean  b6;
 36     private boolean  b7;
 37     private boolean  b8;
 38     private boolean  b9;
 39     
 40     private List<String> list;
 41 
 42     public String getS1() {
 43         return s1;
 44     }
 45 
 46     public void setS1(String s1) {
 47         this.s1 = s1;
 48     }
 49 
 50     public String getS2() {
 51         return s2;
 52     }
 53 
 54     public void setS2(String s2) {
 55         this.s2 = s2;
 56     }
 57 
 58     public String getS3() {
 59         return s3;
 60     }
 61 
 62     public void setS3(String s3) {
 63         this.s3 = s3;
 64     }
 65 
 66     public String getS4() {
 67         return s4;
 68     }
 69 
 70     public void setS4(String s4) {
 71         this.s4 = s4;
 72     }
 73 
 74     public String getS5() {
 75         return s5;
 76     }
 77 
 78     public void setS5(String s5) {
 79         this.s5 = s5;
 80     }
 81 
 82     public String getS6() {
 83         return s6;
 84     }
 85 
 86     public void setS6(String s6) {
 87         this.s6 = s6;
 88     }
 89 
 90     public String getS7() {
 91         return s7;
 92     }
 93 
 94     public void setS7(String s7) {
 95         this.s7 = s7;
 96     }
 97 
 98     public String getS8() {
 99         return s8;
100     }
101 
102     public void setS8(String s8) {
103         this.s8 = s8;
104     }
105 
106     public String getS9() {
107         return s9;
108     }
109 
110     public void setS9(String s9) {
111         this.s9 = s9;
112     }
113 
114     public int getI1() {
115         return i1;
116     }
117 
118     public void setI1(int i1) {
119         this.i1 = i1;
120     }
121 
122     public int getI2() {
123         return i2;
124     }
125 
126     public void setI2(int i2) {
127         this.i2 = i2;
128     }
129 
130     public int getI3() {
131         return i3;
132     }
133 
134     public void setI3(int i3) {
135         this.i3 = i3;
136     }
137 
138     public int getI4() {
139         return i4;
140     }
141 
142     public void setI4(int i4) {
143         this.i4 = i4;
144     }
145 
146     public int getI5() {
147         return i5;
148     }
149 
150     public void setI5(int i5) {
151         this.i5 = i5;
152     }
153 
154     public int getI6() {
155         return i6;
156     }
157 
158     public void setI6(int i6) {
159         this.i6 = i6;
160     }
161 
162     public int getI7() {
163         return i7;
164     }
165 
166     public void setI7(int i7) {
167         this.i7 = i7;
168     }
169 
170     public int getI8() {
171         return i8;
172     }
173 
174     public void setI8(int i8) {
175         this.i8 = i8;
176     }
177 
178     public int getI9() {
179         return i9;
180     }
181 
182     public void setI9(int i9) {
183         this.i9 = i9;
184     }
185 
186     public boolean isB1() {
187         return b1;
188     }
189 
190     public void setB1(boolean b1) {
191         this.b1 = b1;
192     }
193 
194     public boolean isB2() {
195         return b2;
196     }
197 
198     public void setB2(boolean b2) {
199         this.b2 = b2;
200     }
201 
202     public boolean isB3() {
203         return b3;
204     }
205 
206     public void setB3(boolean b3) {
207         this.b3 = b3;
208     }
209 
210     public boolean isB4() {
211         return b4;
212     }
213 
214     public void setB4(boolean b4) {
215         this.b4 = b4;
216     }
217 
218     public boolean isB5() {
219         return b5;
220     }
221 
222     public void setB5(boolean b5) {
223         this.b5 = b5;
224     }
225 
226     public boolean isB6() {
227         return b6;
228     }
229 
230     public void setB6(boolean b6) {
231         this.b6 = b6;
232     }
233 
234     public boolean isB7() {
235         return b7;
236     }
237 
238     public void setB7(boolean b7) {
239         this.b7 = b7;
240     }
241 
242     public boolean isB8() {
243         return b8;
244     }
245 
246     public void setB8(boolean b8) {
247         this.b8 = b8;
248     }
249 
250     public boolean isB9() {
251         return b9;
252     }
253 
254     public void setB9(boolean b9) {
255         this.b9 = b9;
256     }
257 
258     public List<String> getList() {
259         return list;
260     }
261 
262     public void setList(List<String> list) {
263         this.list = list;
264     }
265     
266     public Products(){
267         
268     }
269 
270     public Products(String s1, String s2, String s3, String s4, String s5,
271             String s6, String s7, String s8, String s9, int i1, int i2, int i3,
272             int i4, int i5, int i6, int i7, int i8, int i9, boolean b1,
273             boolean b2, boolean b3, boolean b4, boolean b5, boolean b6,
274             boolean b7, boolean b8, boolean b9, List<String> list) {
275         super();
276         this.s1 = s1;
277         this.s2 = s2;
278         this.s3 = s3;
279         this.s4 = s4;
280         this.s5 = s5;
281         this.s6 = s6;
282         this.s7 = s7;
283         this.s8 = s8;
284         this.s9 = s9;
285         this.i1 = i1;
286         this.i2 = i2;
287         this.i3 = i3;
288         this.i4 = i4;
289         this.i5 = i5;
290         this.i6 = i6;
291         this.i7 = i7;
292         this.i8 = i8;
293         this.i9 = i9;
294         this.b1 = b1;
295         this.b2 = b2;
296         this.b3 = b3;
297         this.b4 = b4;
298         this.b5 = b5;
299         this.b6 = b6;
300         this.b7 = b7;
301         this.b8 = b8;
302         this.b9 = b9;
303         this.list = list;
304     }
305 
306     @Override
307     public String toString() {
308         return "Products [s1=" + s1 + ", s2=" + s2 + ", s3=" + s3 + ", s4="
309                 + s4 + ", s5=" + s5 + ", s6=" + s6 + ", s7=" + s7 + ", s8="
310                 + s8 + ", s9=" + s9 + ", i1=" + i1 + ", i2=" + i2 + ", i3="
311                 + i3 + ", i4=" + i4 + ", i5=" + i5 + ", i6=" + i6 + ", i7="
312                 + i7 + ", i8=" + i8 + ", i9=" + i9 + ", b1=" + b1 + ", b2="
313                 + b2 + ", b3=" + b3 + ", b4=" + b4 + ", b5=" + b5 + ", b6="
314                 + b6 + ", b7=" + b7 + ", b8=" + b8 + ", b9=" + b9 + ", list="
315                 + list + "]";
316     }
317 }
View Code

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;
}
View Code

其中的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;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM