上一篇文章 通信協議序列化解讀(一):http://www.cnblogs.com/tohxyblog/p/8974641.html html
前言:上一面文章咱們介紹了java序列化,以及谷歌protobuf,可是因爲protobuf的使用起來並不像其餘序列化那麼簡單(首先要寫.proto文件,而後編譯.proto文件,生成對應的.java文件),因此即便他是如何的優秀,也仍是沒能搶佔json的份額。
這篇文章咱們要介紹的是一款基於protobuf的java序列化協議——prorostuff,在java端能極大的簡便使用,並且反序列化可由protobuf完成(那麼前端就能夠用其餘語言的protobuf解碼)。前端
protostuff 基於Google protobuf,可是提供了更多的功能和更簡易的用法。其中,protostuff-runtime 實現了無需預編譯對java bean進行protobuf序列化/反序列化的能力。protostuff-runtime的侷限是序列化前需預先傳入schema,反序列化不負責對象的建立只負責複製,於是必須提供默認構造函數。此外,protostuff 還能夠按照protobuf的配置序列化成json/yaml/xml等格式。java
在性能上,protostuff不輸原生的protobuf,甚至有反超之勢。面試
支持protostuff-compiler產生的消息json
支持現有的POJO函數
支持現有的protoc產生的Java消息工具
與各類移動平臺的互操做能力(Android、Kindle、j2me)性能
支持轉碼測試
導包:spa
<!-- //protostuff序列化 --> <dependency> <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-core</artifactId> <version>1.0.8</version> </dependency> <dependency> <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> <version>1.0.8</version> </dependency> <!-- Objenesis --> <dependency> <groupId>org.objenesis</groupId> <artifactId>objenesis</artifactId> <version>2.1</version> </dependency>
工具類:
package com.result.base.tools; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.objenesis.Objenesis; import org.objenesis.ObjenesisStd; import com.dyuproject.protostuff.LinkedBuffer; import com.dyuproject.protostuff.ProtobufIOUtil; import com.dyuproject.protostuff.ProtostuffIOUtil; import com.dyuproject.protostuff.Schema; import com.dyuproject.protostuff.runtime.RuntimeSchema; /** * @author 做者 huangxinyu * @version 建立時間:2018年1月9日 下午7:41:24 * Protostuff序列化工具 */ public class SerializationUtil { private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>(); private static Objenesis objenesis = new ObjenesisStd(true); private SerializationUtil() { } @SuppressWarnings("unchecked") private static <T> Schema<T> getSchema(Class<T> cls) { Schema<T> schema = (Schema<T>) cachedSchema.get(cls); if (schema == null) { schema = RuntimeSchema.createFrom(cls); if (schema != null) { cachedSchema.put(cls, schema); } } return schema; } @SuppressWarnings("unchecked") public static <T> String serializeToString(T obj) { Class<T> cls = (Class<T>) obj.getClass(); LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); try { Schema<T> schema = getSchema(cls); return new String(ProtobufIOUtil.toByteArray(obj, schema, buffer), "ISO8859-1"); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } finally { buffer.clear(); } } public static <T> T deserializeFromString(String data, Class<T> cls) { try { T message = (T) objenesis.newInstance(cls); Schema<T> schema = getSchema(cls); ProtobufIOUtil.mergeFrom(data.getBytes("ISO8859-1"), message, schema); return message; } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @SuppressWarnings("unchecked") public static <T> byte[] serializeToByte(T obj) { Class<T> cls = (Class<T>) obj.getClass(); LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); try { Schema<T> schema = getSchema(cls); return ProtobufIOUtil.toByteArray(obj, schema, buffer); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } finally { buffer.clear(); } } public static <T> T deserializeFromByte(byte[] data, Class<T> cls) { try { T message = (T) objenesis.newInstance(cls); Schema<T> schema = getSchema(cls); ProtobufIOUtil.mergeFrom(data, message, schema); return message; } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } }
4.1 測試環境
xstraem版本:1.3.1
protobuf-java版本:3.0.0-alpha-2
java版本:1.7
-Xms2048m
-Xmx2048m
4.2 測試工具
用時: 控制檯輸出時間
CPU&內存: jconsole
文件大小: 文件屬性
4.3 說明
測試中,xml和protoBuf和protostuff三種測試所使用的JavaBean所擁有的字段類型相同、字段數量相同(約28個)、字段所附的值相同、都包含有一個List<String>字段,用List字段的size來控制JavaBean對象的大小。本次測試中size=100
4.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個對象 |
引用最後一組數據的直方圖:
4.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。