Protostuff序列化


前言:

       Java序列化是Java技術體系當中的一個重要議題,序列化的意義在於信息的交換和存儲,通常會和io、持久化、rmi技術有關(eg:一些orm框架會要求持久化的對象類型實現Serializable接口)。

       本文將提供Java自帶序列化機制和ProtoStuff的序列化(僅僅當作一種數據格式)的比較,從序列化的內容和特點來對二者進行比較。

       結論:1,Java序列化對象時不需要通過屬性的get set方法或其它無關序列化內部定義的方法(比如readObject,writeObject是內置的序列化方法),序列化也不需要get set方法支持,反序列化是構造對象的一種手段。

               2,Java序列化時類型必須完全匹配(全路徑類名+序列化id)。

               3,Protostuff反序列化時並不要求類型匹配,比如包名、類名甚至是字段名,它僅僅需要序列化類型A 和反序列化類型B 的字段類型可轉換(比如int可以轉換為long)即可。

 

java.io.Serializable

       標識一個對象需要系列化,該對象類型需要實現 Serializable 接口。關於序列化的認識,可以參考IBM社區的文章《Java序列化的高級認識》,本文直接拿該文檔的結論。

       1,序列化的類型和反序列化的類型的序列化ID必須一致(遠程信息交換時)。

       2,靜態數據不會被序列化,Transient關鍵字修飾的字段不會被序列化。

       3,對象序列化存儲時,兩次存儲相同值對象會有優化(第二次對象寫入會只存儲引用)。

 

ProtostuffUtil

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

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

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

}

 

 

ProtostuffTest

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Random;

import org.apache.commons.lang.StringUtils;

public class ProtostuffTest {

    /** 產生一個隨機的字符串*/
    public static String randomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        int strlen = str.length();
        Random random = new Random();
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int num = random.nextInt(strlen);
            buf.append(str.charAt(num));
        }
        return buf.toString();
    }

    private static ResourceObj getObj(String name, String path, int contentSize) {
        ResourceObj obj = new ResourceObj(name, path, "");
        obj.setContent(randomString(contentSize));
        return obj;
    }

    private static long speedTest(int contentSize, int times) {
        ResourceObj obj = getObj("lb.conf", "/home/admin/conf/lb", contentSize);
        long start = System.currentTimeMillis();
        for (int i = 0; i < times; i++) {
            byte[] bytes = ProtostuffUtil.serializer(obj);
            ProtostuffUtil.deserializer(bytes, ResourceObj.class);
        }
        long end = System.currentTimeMillis();
        return end - start;
    }

    private static long speedTestOrg(int contentSize, int times) throws IOException,
                                                                ClassNotFoundException {
        ResourceObj obj = getObj("lb.conf", "/home/admin/conf/lb", contentSize);
        long start = System.currentTimeMillis();
        for (int i = 0; i < times; i++) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            byte[] bytes = baos.toByteArray();

            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            ois.readObject();
        }
        long end = System.currentTimeMillis();
        return end - start;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        System.out.println(speedTestOrg(9999999, 1));
        System.out.println(speedTest(9999999, 1));
    }

    private static void test() {
        ResourceObj obj = getObj("lb.conf", "/home/admin/conf/lb", 88888);
        byte[] bytes = ProtostuffUtil.serializer(obj);

        ResourceObj obj2 = ProtostuffUtil.deserializer(bytes, ResourceObj.class);
        System.out.println(obj2.getFilename());
        System.out.println(obj2.getPath());
        System.out.println(StringUtils.equals(obj.getContent(), obj2.getContent()));
    }

}

 

 

結果

size:10000000
java-build-in:189ms
protostaff:237ms

size:100000000
java-build-in:1661ms
protostaff:792ms

 

  

自己測試的結果:

1、在對象較小的時候,還是java自帶的序列化比較快。10M之下的時候。(沒有考慮對象的復雜度)

2、文件較大時,protostuff比較快。(protostuff-runtime方式,用protostuff可能會更快,只是沒這么方便)

 

Google 的protobuf是一個優秀的序列化工具,跨語言、快速、序列化后體積小。

protobuf的一個缺點是需要數據結構的預編譯過程,首先要編寫.proto格式的配置文件,再通過protobuf提供的工具生成各種語言響應的代碼。由於java具有反射和動態代碼生成的能力,這個預編譯過程不是必須的,可以在代碼執行時來實現。有個protostuff(http://code.google.com/p/protostuff/)已經實現了這個功能。

protostuff基於Google protobuf,但是提供了更多的功能和更簡易的用法。其中,protostuff-runtime實現了無需預編譯對java bean進行protobuf序列化/反序列化的能力。

 

protostuff-runtime的局限是序列化前需預先傳入schema,反序列化不負責對象的創建只負責復制,因而必須提供默認構造函數。

此外,protostuff還可以按照protobuf的配置序列化成json/yaml/xml等格式。

 

參考:

Zookeeper實現簡單的分布式RPC框架

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM