Protostuff一键序列化工具、Protobuf JAVA实现

Stella981
• 阅读 568

前言:由于搜集网络,发现Protostuff相关内容较少,故此发布这篇文章

1. 何为序列化

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

序列化使其他代码可以查看或修改那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 SecurityPermission。在默认策略下,通过 Internet 下载的代码或 Internet 代码不会授予该权限;只有本地计算机上的代码才被授予该权限。

通常,对象实例的所有字段都会被序列化,这意味着数据会被表示为实例的序列化数据。这样,能够解释该格式的代码有可能能够确定这些数据的值,而不依赖于该成员的可访问性。类似地,反序列化从序列化的表示形式中提取数据,并直接设置对象状态,这也与可访问性规则无关。

对于任何可能包含重要的安全性数据的对象,如果可能,应该使该对象不可序列化。如果它必须为可序列化的,请尝试生成特定字段来保存不可序列化的重要数据。如果无法实现这一点,则应注意该数据会被公开给任何拥有序列化权限的代码,并确保不让任何恶意代码获得该权限。

2. 常见的序列化有哪些

Xml、Json、JDK传统序列化、Protobuf序列化  (随口举例,笔者也懒得去收集了)

3. 序列化体积对比

理论分析结论:Xml >或< Jdk原生> Json > Protobuf

其中在某些特殊场景下,Json可能大于Jdk,Xml可能大于或小于Jdk。

原理分析:传统的Xml序列化,以字段名开头,字段名结尾,存在一个字段冗余,在某些特定的级别格式下,Xml报文长度过量冗余。

:Json序列化,某些Json序列化可能将空字段也序列化出来,如:{“user”:”null”},在过滤空的场景下,Json序列化内容比Jdk传统序列化体积小

:Jdk传统序列化,即实现Serializable接口的对象或数据模型转化为Byte数组,内容包含类信息、字段信息等,故此体积较大

:Protobuf序列化,讲对象或数据模型中有效的内容转化成Byte数组,不包括类信息与数据模型,再反序列化时需要指定目标数据结构,根据数据结构类型对应反序列化,由于仅仅包含内容,故此体积最小

4. 序列效率对比

根据第3点理论原理分析我们不难看出来,xml和json实际效率相差不多,可能就在于xml稍多的内容读写,故此xml效率低于json

由于json序列化和反序列化是完全基于反射,故此,json效率低于Jdk原生序列化

Jdk原生序列化属于基于半反射完成,效率高于Json

而Protobuf,相比jdk原生序列化来说,少做了很多事情,故此Protobuf效率较jdk原生序列化高出很多(排除谷歌对Protobuf的特定算法带来的优势)。

5. 图标分析

笔者并非传说中的那么蛋疼,故此在网络收集相关评测结果。

来源:http://blog.csdn.net/antgan/article/details/52103966

详细评测:http://www.52im.net/thread-772-1-1.html

6. 在JAVA中如何使用

maven引入:

        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>1.0.12</version>
        </dependency>
        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>1.0.12</version>
        </dependency>

工具类:

package com.protobuf.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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;

@SuppressWarnings("unchecked")
public class ProtobufUtil {
    

    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();
    
    private static Map<Class<?>, Field> wrapperMap = new ConcurrentHashMap<Class<?>, Field>();
    
    private static Map<Class<?>, Object> unWrapperMap = new ConcurrentHashMap<Class<?>, Object>();
    
    
    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;
    }

    /**
     * 序列化
     * 
     * @param obj
     * @return
     */
    public static <T> byte[] serialize(T obj) {
        if (isNullOrEmpty(obj)) {
            return null;
        }
        try {
            if(List.class.isAssignableFrom(obj.getClass())){
                List<T> list=(List<T>)obj;
                Class<?> clazz=list.get(0).getClass();
                byte [] data=serializeList(list);
                CustomWrapper wrapper=new CustomWrapper(clazz,data);
                return serializeT(wrapper);
            }
            if(Set.class.isAssignableFrom(obj.getClass())){
                List<T> list=new ArrayList<T>((Set<T>)obj);
                Class<?> clazz=list.get(0).getClass();
                byte [] data=serializeList(list);
                CustomWrapper wrapper=new CustomWrapper(clazz,data);
                return serializeT(wrapper);
            }
            if(ValueWrapper.isSpecialType(obj.getClass())){
                ValueWrapper wrapper=new ValueWrapper(obj);
                return serializeT(wrapper);
            }
            return serializeT(obj);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
    }
      public static <T> byte[] serializeList(List<T> objList) {
            if (objList == null || objList.isEmpty()) {
                throw new RuntimeException("序列化对象列表(" + objList + ")参数异常!");
            }
            Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());
            LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
            byte[] protostuff = null;
            ByteArrayOutputStream bos = null;
            try {
                bos = new ByteArrayOutputStream();
                ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
                protostuff = bos.toByteArray();
            } catch (Exception e) {
                throw new RuntimeException("序列化对象列表(" + objList + ")发生异常!", e);
            } finally {
                buffer.clear();
                try {
                    if(bos!=null){
                        bos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return protostuff;
        }

    private static <T> byte[] serializeT(T obj) {
        Class<T> cls = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.MIN_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();
        }
    }


    /**
     * 反序列化
     * 
     * @param data
     * @param cls
     * @return
     */
    
    public static <T> T unSerialize(byte[] data,Class<?> clazz) {
        if (isNullOrEmpty(data)) {
            return null;
        }
        try {
            if(List.class.isAssignableFrom(clazz)){
                CustomWrapper wrapper= unSerializeT(data, CustomWrapper.class);
                return (T) unSerializeList(data, wrapper.getClazz());
            }
            if(Set.class.isAssignableFrom(clazz)){
                CustomWrapper wrapper= unSerializeT(data, CustomWrapper.class);
                return (T) unSerializeSet(data, wrapper.getClazz());
            }
            if(ValueWrapper.isSpecialType(clazz)){
                ValueWrapper wrapper= unSerializeT(data, ValueWrapper.class);
                if(wrapper==null||isNullOrEmpty(wrapper)){
                    return null;
                }
                return wrapper.getValue();
            }
            return (T) unSerializeT(data, clazz);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
    }
     public static <T> Set<T> unSerializeSet(byte[] data, Class<T> clazz) {
           if (data == null || data.length == 0) {
                throw new RuntimeException("反序列化对象发生异常,byte序列为空!");
            }
       
            Schema<T> schema = RuntimeSchema.getSchema(clazz);
            try {
               List<T> list = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(data), schema);
               return new HashSet<T>(list);
            } catch (IOException e) {
                throw new RuntimeException("反序列化对象列表发生异常!",e);
            }
        }

      public static <T> List<T> unSerializeList(byte[] data, Class<T> clazz) {
           if (data == null || data.length == 0) {
                throw new RuntimeException("反序列化对象发生异常,byte序列为空!");
            }
       
            Schema<T> schema = RuntimeSchema.getSchema(clazz);
            List<T> result = null;
            try {
                result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(data), schema);
            } catch (IOException e) {
                throw new RuntimeException("反序列化对象列表发生异常!",e);
            }
            return result;
        }
    private static <T> T unSerializeT(byte[] data, Class<T> cls) {
        try {
            T message = cls.newInstance();
            Schema<T> schema = getSchema(cls);
            ProtostuffIOUtil.mergeFrom(data, message, schema);
            return message;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
    
    
    public static boolean isNullOrEmpty(Object obj) {
        try {
            if (obj == null)
                return true;
            if (obj instanceof CharSequence) {
                return ((CharSequence) obj).length() == 0;
            }
            if (obj instanceof Collection) {
                return ((Collection<?>) obj).isEmpty();
            }
            if (obj instanceof Map) {
                return ((Map<?, ?>) obj).isEmpty();
            }
            if (obj instanceof Object[]) {
                Object[] object = (Object[]) obj;
                if (object.length == 0) {
                    return true;
                }
                boolean empty = true;
                for (int i = 0; i < object.length; i++) {
                    if (!isNullOrEmpty(object[i])) {
                        empty = false;
                        break;
                    }
                }
                return empty;
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return true;
        }

    }
    
    
    @SuppressWarnings({  "serial" })
    public static class CustomWrapper  implements Serializable{
        
        private Class<?> clazz;
        
        private byte []data;
        
        public CustomWrapper(){}
        
        public CustomWrapper(Class<?> clazz,byte[] data){
            this.clazz=clazz;
            this.data=data;
        }
        
        public byte[] getData() {
            return data;
        }

        public void setData(byte[] data) {
            this.data = data;
        }

        public Class<?> getClazz() {
            return clazz;
        }

        public void setClazz(Class<?> clazz) {
            this.clazz = clazz;
        }
        
        
    }
    
    
    @SuppressWarnings({ "rawtypes", "serial", "unused" })
    public static class ValueWrapper implements Serializable{
        

        private Map mapValue;
        
        private List listValue;
        
        private Collection collectionValue;
        
        private Iterable iterableValue;
        
        private Set setValue;
        
        private String stringValue;
        
        private Byte byteValue;
        
        private Short shortValue;
        
        private Long longValue;
        
        private Integer integerValue;
        
        private Double doubleValue;
        
        private Float floatValue;
        
        private Character characterValue;
        
        private Boolean booleanValue;
        

        public ValueWrapper(){}
        
        public ValueWrapper(Object data) throws IllegalArgumentException, IllegalAccessException {
            if (data == null) {
                return;
            }
                if (isNullOrEmpty(wrapperMap)) {
                    initFiledType();
                }
                if (wrapperMap.containsKey(data.getClass())) {
                    Field f = wrapperMap.get(data.getClass());
                    f.setAccessible(true);
                    f.set(this, data);
                }
                for (Class<?> clazz : wrapperMap.keySet()) {
                    if (!clazz.isAssignableFrom(data.getClass())) {
                        continue;
                    }
                    Field f = wrapperMap.get(clazz);
                    f.setAccessible(true);
                    f.set(this, data);
                    wrapperMap.put(data.getClass(), f);
                    return;
                }
        }

        public static  boolean isSpecialType(Class<?> clazz){
            if (isNullOrEmpty(wrapperMap)) {
                initFiledType();
            }
            if(unWrapperMap.containsKey(clazz)){
                return false;
            }
            if(wrapperMap.containsKey(clazz)){
                return true;
            }
            for (Class<?> clazzTmp : wrapperMap.keySet()) {
                if (!clazzTmp.isAssignableFrom(clazz)) {
                    continue;
                }
                Field f = wrapperMap.get(clazzTmp);
                f.setAccessible(true);
                wrapperMap.put(clazz, f);
                return true;
            }
            unWrapperMap.put(clazz, clazz);
            return false;
        }
        private static void initFiledType() {
            Field[] fields = ValueWrapper.class.getDeclaredFields();
            for (Field f : fields) {
                wrapperMap.put(f.getType(), f);
            }
        }

        public <T> T getValue() throws IllegalArgumentException, IllegalAccessException {
                for (Class<?> clazz : wrapperMap.keySet()) {
                    T result = (T) wrapperMap.get(clazz).get(this);
                    if (isNullOrEmpty(result)) {
                        continue;
                    }
                    return result;
                }
                return null;
        }

    }
    
    
}

测试图:

Protostuff一键序列化工具、Protobuf JAVA实现

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这