Protostuff序列化和反序列化

Java序列化和反序列化

         Java序列化是Java技術體系當中的一個重要議題,序列化和反序列化是在應對網絡編程最常遇到的問題之一。序列化的意義在於信息的交換和存儲,一般會和io、持久化、rmi技術有關(eg:一些orm框架會要求持久化的對象類型實現Serializable接口),咱們也能夠序列化時將Java Object轉成byte[];反序列化時將byte[]轉成Java Object。及Protostuff的實現方法。
        此時,可能有些朋友已經想到了JDK serializable的序列化方式,既然JDK已經有現成的方法了,爲何還要使用Protostuff ? 咱們先對常見的序列化方式作一下對比你就知道了。java

序列化框架性能對比(kryo、hessian、java、protostuff)git

簡介:github

 

優勢編程

缺點json

Kryo數組

速度快,序列化後體積小緩存

跨語言支持較複雜網絡

Hessian框架

默認支持跨語言jvm

較慢

Protostuff

速度快,基於protobuf

需靜態編譯

Protostuff-Runtime

無需靜態編譯,但序列化前需預先傳入schema

不支持無默認構造函數的類,反序列化時需用戶本身初始化序列化後的對象,其只負責將該對象進行賦值

Java

使用方便,可序列化全部類

速度慢,佔空間

     
     
     

 

測試環境:

硬件信息:

         16 Intel(R) Xeon(R) CPU E5620 @2.40GHz

         Red Hat Enterprise Linux Server release 5.4 (Tikanga)

         java:  "1.6.0_27" Java HotSpot(TM) 64-Bit Server VM (build 20.2-b06, mixed mode)

         JVM options: java -Xmx256m –server

測試數據:(見附件)

         ArrayList.class

         MediaContent.class

         Media.class

         Image.class

測試方法:(參考自https://github.com/eishay/jvm-serializers

<!--[if !supportLists]-->一、  <!--[endif]-->在正式測試以前,將測試用例運行10次對JVM進行預熱。

<!--[if !supportLists]-->二、  <!--[endif]-->對測試用例的每一個方法,運行2000次,取平均值。

<!--[if !supportLists]-->三、  <!--[endif]-->每次測試用例運行500次,取最優結果

測試基準:

         ser:           建立一個對象,並將其序列化成byte數組的時間

         deser:       將byte數組反序列化成對象的時間

         total:        建立一個對象,將其序列化成byte數組再反序列化爲對象的總時間

         size:          序列化後的數組大小

         size+dfl:   序列化後用level6級別的zlib進行壓縮後的大小

測試工具:

序列化工具

序列化方式

kryo

使用kryo默認的序列化方式fieldSerializer,

對須要序列化的對象採起默認的操做。開啓reference,關閉register

protostuff

使用靜態編譯生成的Schema進行序列化

protostuff-runtime

使用protostuff-runtime框架生成Schema進行序列化

   

 

 

測試結果:

         時間:


 

         大小:


總結:

         Kryo在類註冊且reference關閉的狀況下,序列化速度和大小明顯 優於hessian和java,接近於protostuff。開啓reference後將序列化速度將明顯變慢,但仍舊優於hessian。

相關知識:

         類註冊:將須要序列化的類註冊到kryo中,能夠提升序列化與反序列化的速度。

         Reference:開啓這個選項後,相同的對象將被序列化爲同一個byte[],默認關閉,若是要支持循環引用,則必須開啓

穩定性測試:

    測試用例(見附件)

         循環引用:Cyclic.java

序列化方式

無默認構造函數

循環引用

對象爲null

是否須要預先知道對象所屬的類

大對象(4M)

Kryo

支持

需將reference選項打開

支持

不須要,關閉register

支持

Java

支持

支持

支持

不須要

支持

Protostuff

支持

支持

支持

不須要

支持

Protostuff

-runtime

不支持

支持

支持

須要

支持

Hessian

支持

支持

支持

不須要

支持

經過對比咱們發現Protostuff仍是很是強悍的,性能、穩定性、友好性都是很是好得,那麼就讓咱們學習一下Protostuff吧。

Protostuff簡介

Protostuff的項目主頁:http://www.protostuff.io/

Protostuff是一個序列化庫,支持一下序列化格式:

  • protobuf
  • protostuff(本地)
  • graph
  • json
  • smile
  • xml
  • yaml
  • kvp

序列化和反序列化工具

序列化

@SuppressWarnings("unchecked")
public static <T> byte[] serialize(T obj) {
    Class<T> cls = (Class<T>) obj.getClass();
    LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
    try {
        Schema<T> schema = getSchema(cls);
        return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } catch (Exception e) {
        throw new IllegalStateException(e.getMessage(), e);
    } finally {
        buffer.clear();
    }
}

第3行:得到對象的類;
第4行:使用LinkedBuffer分配一塊默認大小的buffer空間;
第6行:經過對象的類構建對應的schema;
第7行:使用給定的schema將對象序列化爲一個byte數組,並返回。

反序列化

public static <T> T deserialize(byte[] data, Class<T> cls) {
    try {
        T message = objenesis.newInstance(cls);
        Schema<T> schema = getSchema(cls);
        ProtostuffIOUtil.mergeFrom(data, message, schema);
        return message;
    } catch (Exception e) {
        throw new IllegalStateException(e.getMessage(), e);
    }
}

第3行:使用objenesis實例化一個類的對象;
第4行:經過對象的類構建對應的schema;
第5,6行:使用給定的schema將byte數組和對象合併,並返回。

構建schema

構建schema的過程可能會比較耗時,所以但願使用過的類對應的schema能被緩存起來。代碼以下,再也不贅述:

private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<>();

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

能夠看到方法第4行使用了RuntimeSchema,關於RuntimeSchema的用法參考例子:

eg:

<!--protostuff序列化依賴-->
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.1.2</version>
</dependency>
package com.jhaso.shopping.util;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 俠客人生
 * @ClassName ProtostuffUtil
 * @Description Protostuff序列化工具類
 * @create 2017-08-10 22:23
 * @version: V1.0.0
 **/
public class ProtostuffUtil {

    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        @SuppressWarnings("unchecked")
        Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.getSchema(clazz);
            if (schema != null) {
                cachedSchema.put(clazz, schema);
            }
        }
        return schema;
    }

    /**
     * 序列化
     *
     * @param obj
     * @return
     */
    public static <T> byte[] serializer(T obj) {
        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(clazz);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化
     *
     * @param data
     * @param clazz
     * @return
     */
    public static <T> T deserializer(byte[] data, Class<T> clazz) {
        try {
            T obj = clazz.newInstance();
            Schema<T> schema = getSchema(clazz);
            ProtostuffIOUtil.mergeFrom(data, obj, schema);
            return obj;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}
相關文章
相關標籤/搜索