zoukankan      html  css  js  c++  java
  • 通讯协议序列化解读(二) protostuff详解教程

    上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html 

    前言:上一面文章我们介绍了java序列化,以及谷歌protobuf,但是由于protobuf的使用起来并不像其他序列化那么简单(首先要写.proto文件,然后编译.proto文件,生成对应的.java文件),所以即使他是如何的优秀,也还是没能抢占json的份额。
    这篇文章我们要介绍的是一款基于protobuf的java序列化协议——prorostuff,在java端能极大的简便使用,而且反序列化可由protobuf完成(那么前端就可以用其他语言的protobuf解码)。

    一、protostuff介绍

    protostuff 基于Google protobuf,但是提供了更多的功能和更简易的用法。其中,protostuff-runtime 实现了无需预编译对java bean进行protobuf序列化/反序列化的能力。protostuff-runtime的局限是序列化前需预先传入schema,反序列化不负责对象的创建只负责复制,因而必须提供默认构造函数。此外,protostuff 还可以按照protobuf的配置序列化成json/yaml/xml等格式。

    在性能上,protostuff不输原生的protobuf,甚至有反超之势。

    二、Protostuff特征

    1. 支持protostuff-compiler产生的消息

    2. 支持现有的POJO

    3. 支持现有的protoc产生的Java消息

    4. 与各种移动平台的互操作能力(Android、Kindle、j2me)

    5. 支持转码

    三、工具类实现

    导包:

    <!-- //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、序列化:

      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。

  • 相关阅读:
    函数式宏定义与普通函数
    linux之sort用法
    HDU 4390 Number Sequence 容斥原理
    HDU 4407 Sum 容斥原理
    HDU 4059 The Boss on Mars 容斥原理
    UVA12653 Buses
    UVA 12651 Triangles
    UVA 10892
    HDU 4292 Food
    HDU 4288 Coder
  • 原文地址:https://www.cnblogs.com/tohxyblog/p/8974636.html
Copyright © 2011-2022 走看看