項目中http通訊離不開對象的序列化和反序列化,經過序列化技術,能夠誇語言實現數據的傳輸,例如把一個對象序列化後的二進制數據、xml格式數據存在文本文件,下次經過讀取文件,而後反序列化一下便可從新生成該對象,抑或經過網絡把序列化後的數據傳輸到另外一個終端,對方經過反序列化後也能夠從新複製出一個大概相同的對象出來。html
在通常項目中,xml是一個不錯的選擇,例如微信公衆平臺的大多數接口,就是使用xml技術來序列化傳輸的,學習成本低,可讀性高,方便調試,能夠直接在瀏覽器查看結果等等都是他的優勢,對於對速度要求不高的系統來講,的確是一種不錯的選擇。但若是系統對序列化效率要求很高,例如想比xml快上10倍?那麼可能就得考慮換成其餘技術了,例如——protobuf。java
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.1 測試環境網絡
xstraem版本:1.3.1微信公衆平臺
protobuf-java版本:3.0.0-alpha-2eclipse
java版本:1.7編輯器
-Xms2048mide
-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 |
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.一、速度上:protostuff比protobuf快3倍左右,protobuf比xml快4-5倍,該倍數隨着序列化對象的增長,基本保持不變。
1.二、CPU上:protostuff佔用最少,protobuf其次,xml最後。
1.三、內存上:protostuff佔用最少,protobuf其次,xml最後。
1.四、生成文件大小:protostuff佔用最少,protobuf其次,xml最後,前面二者是後者的1/4左右。
二、反序列化
2.一、速度上:在反序列化對象數量較少的狀況下,protobuf比protostuff快1/4左右,比xml快10+倍。但隨着對象數量的增長,protobuf發生了速率明顯變慢的狀況!從而被protostuff趕超。
2.二、CPU上:protostuff佔用最少,protobuf其次,xml最後。
2.三、內存上:protostuff佔用最少,protobuf其次,xml最後。
三、總結
在各個方面上,protostuff的優點很是面試,而protobuf也不弱,考慮用來代替xml。
3.1 準備
jar包:pom.xml:
<!-- xstream --> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> <version>1.3.1</version> </dependency>
3.2 代碼
一、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 }
二、序列化:
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; }
三、反序列化
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.一、快速入門:
下載.exe編譯器——編寫.proto文件——利用編譯器編譯.proto文件生成javabean——引用jar包——直接使用javabean自帶的序列化、反序列化方法
一、下載針對java的.exe編譯器
protobuf編譯器官方下載地址:https://developers.google.com/protocol-buffers/docs/downloads
下載不了的:點我
二、編寫.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
三、利用編譯器編譯.proto文件生成javabean
把.proto文件放在.exe同個目錄下面,打開cmd,進入同目錄下,執行命令:
protoc.exe --java_out=./ test.proto
假如.proto文件沒有編寫錯誤的話,成功後在同目錄下即有javabean的類生成。
四、引用jar包
jar包地址pom.xml:
<!-- protobuf --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.0.0-alpha-2</version> </dependency>
五、把剛剛生成的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.1 快速入門
引用jar包——學習語法——直接使用
一、引用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>
二、javabean:
同上面xml的javabean
三、序列化例子:
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; }
四、反序列化例子:
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; }