Protostuff一鍵序列化工具、Protobuf JAVA實現

 

前言:由於蒐集網絡,發現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;
		}

	}
	
	
}

 

 

測試圖:

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章