通信協議序列化解讀(二) protostuff詳解教程

上一篇文章 通信協議序列化解讀(一):http://www.cnblogs.com/tohxyblog/p/8974641.html html

前言:上一面文章咱們介紹了java序列化,以及谷歌protobuf,可是因爲protobuf的使用起來並不像其餘序列化那麼簡單(首先要寫.proto文件,而後編譯.proto文件,生成對應的.java文件),因此即便他是如何的優秀,也仍是沒能搶佔json的份額。
這篇文章咱們要介紹的是一款基於protobuf的java序列化協議——prorostuff,在java端能極大的簡便使用,並且反序列化可由protobuf完成(那麼前端就能夠用其餘語言的protobuf解碼)。前端

1、protostuff介紹

protostuff 基於Google protobuf,可是提供了更多的功能和更簡易的用法。其中,protostuff-runtime 實現了無需預編譯對java bean進行protobuf序列化/反序列化的能力。protostuff-runtime的侷限是序列化前需預先傳入schema,反序列化不負責對象的建立只負責複製,於是必須提供默認構造函數。此外,protostuff 還能夠按照protobuf的配置序列化成json/yaml/xml等格式。java

在性能上,protostuff不輸原生的protobuf,甚至有反超之勢。面試

2、Protostuff特徵

  1. 支持protostuff-compiler產生的消息json

  2. 支持現有的POJO函數

  3. 支持現有的protoc產生的Java消息工具

  4. 與各類移動平臺的互操做能力(Android、Kindle、j2me)性能

  5. 支持轉碼測試

3、工具類實現

導包: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、性能測試

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。

相關文章
相關標籤/搜索