前言:由于搜集网络,发现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引入:
1 <dependency> 2 <groupId>com.dyuproject.protostuff</groupId> 3 <artifactId>protostuff-core</artifactId> 4 <version>1.0.12</version> 5 </dependency> 6 <dependency> 7 <groupId>com.dyuproject.protostuff</groupId> 8 <artifactId>protostuff-runtime</artifactId> 9 <version>1.0.12</version> 10 </dependency>
工具类:
1package com.protobuf.util; 2 3import java.io.ByteArrayInputStream; 4import java.io.ByteArrayOutputStream; 5import java.io.IOException; 6import java.io.Serializable; 7import java.lang.reflect.Field; 8import java.util.ArrayList; 9import java.util.Collection; 10import java.util.HashSet; 11import java.util.List; 12import java.util.Map; 13import java.util.Set; 14import java.util.concurrent.ConcurrentHashMap; 15 16import com.dyuproject.protostuff.LinkedBuffer; 17import com.dyuproject.protostuff.ProtostuffIOUtil; 18import com.dyuproject.protostuff.Schema; 19import com.dyuproject.protostuff.runtime.RuntimeSchema; 20 21@SuppressWarnings("unchecked") 22public class ProtobufUtil { 23 24 25 private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>(); 26 27 private static Map<Class<?>, Field> wrapperMap = new ConcurrentHashMap<Class<?>, Field>(); 28 29 private static Map<Class<?>, Object> unWrapperMap = new ConcurrentHashMap<Class<?>, Object>(); 30 31 32 private static <T> Schema<T> getSchema(Class<T> cls) { 33 Schema<T> schema = (Schema<T>) cachedSchema.get(cls); 34 if (schema == null) { 35 schema = RuntimeSchema.createFrom(cls); 36 if (schema != null) { 37 cachedSchema.put(cls, schema); 38 } 39 } 40 return schema; 41 } 42 43 /** 44 * 序列化 45 * 46 * @param obj 47 * @return 48 */ 49 public static <T> byte[] serialize(T obj) { 50 if (isNullOrEmpty(obj)) { 51 return null; 52 } 53 try { 54 if(List.class.isAssignableFrom(obj.getClass())){ 55 List<T> list=(List<T>)obj; 56 Class<?> clazz=list.get(0).getClass(); 57 byte [] data=serializeList(list); 58 CustomWrapper wrapper=new CustomWrapper(clazz,data); 59 return serializeT(wrapper); 60 } 61 if(Set.class.isAssignableFrom(obj.getClass())){ 62 List<T> list=new ArrayList<T>((Set<T>)obj); 63 Class<?> clazz=list.get(0).getClass(); 64 byte [] data=serializeList(list); 65 CustomWrapper wrapper=new CustomWrapper(clazz,data); 66 return serializeT(wrapper); 67 } 68 if(ValueWrapper.isSpecialType(obj.getClass())){ 69 ValueWrapper wrapper=new ValueWrapper(obj); 70 return serializeT(wrapper); 71 } 72 return serializeT(obj); 73 } catch (Exception e) { 74 e.printStackTrace(); 75 return null; 76 } 77 78 } 79 public static <T> byte[] serializeList(List<T> objList) { 80 if (objList == null || objList.isEmpty()) { 81 throw new RuntimeException("序列化对象列表(" + objList + ")参数异常!"); 82 } 83 Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass()); 84 LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024); 85 byte[] protostuff = null; 86 ByteArrayOutputStream bos = null; 87 try { 88 bos = new ByteArrayOutputStream(); 89 ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer); 90 protostuff = bos.toByteArray(); 91 } catch (Exception e) { 92 throw new RuntimeException("序列化对象列表(" + objList + ")发生异常!", e); 93 } finally { 94 buffer.clear(); 95 try { 96 if(bos!=null){ 97 bos.close(); 98 } 99 } catch (IOException e) { 100 e.printStackTrace(); 101 } 102 } 103 return protostuff; 104 } 105 106 private static <T> byte[] serializeT(T obj) { 107 Class<T> cls = (Class<T>) obj.getClass(); 108 LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.MIN_BUFFER_SIZE); 109 try { 110 Schema<T> schema = getSchema(cls); 111 return ProtostuffIOUtil.toByteArray(obj, schema, buffer); 112 } catch (Exception e) { 113 throw new IllegalStateException(e.getMessage(), e); 114 } finally { 115 buffer.clear(); 116 } 117 } 118 119 120 /** 121 * 反序列化 122 * 123 * @param data 124 * @param cls 125 * @return 126 */ 127 128 public static <T> T unSerialize(byte[] data,Class<?> clazz) { 129 if (isNullOrEmpty(data)) { 130 return null; 131 } 132 try { 133 if(List.class.isAssignableFrom(clazz)){ 134 CustomWrapper wrapper= unSerializeT(data, CustomWrapper.class); 135 return (T) unSerializeList(data, wrapper.getClazz()); 136 } 137 if(Set.class.isAssignableFrom(clazz)){ 138 CustomWrapper wrapper= unSerializeT(data, CustomWrapper.class); 139 return (T) unSerializeSet(data, wrapper.getClazz()); 140 } 141 if(ValueWrapper.isSpecialType(clazz)){ 142 ValueWrapper wrapper= unSerializeT(data, ValueWrapper.class); 143 if(wrapper==null||isNullOrEmpty(wrapper)){ 144 return null; 145 } 146 return wrapper.getValue(); 147 } 148 return (T) unSerializeT(data, clazz); 149 } catch (Exception e) { 150 e.printStackTrace(); 151 return null; 152 } 153 154 } 155 public static <T> Set<T> unSerializeSet(byte[] data, Class<T> clazz) { 156 if (data == null || data.length == 0) { 157 throw new RuntimeException("反序列化对象发生异常,byte序列为空!"); 158 } 159 160 Schema<T> schema = RuntimeSchema.getSchema(clazz); 161 try { 162 List<T> list = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(data), schema); 163 return new HashSet<T>(list); 164 } catch (IOException e) { 165 throw new RuntimeException("反序列化对象列表发生异常!",e); 166 } 167 } 168 169 public static <T> List<T> unSerializeList(byte[] data, Class<T> clazz) { 170 if (data == null || data.length == 0) { 171 throw new RuntimeException("反序列化对象发生异常,byte序列为空!"); 172 } 173 174 Schema<T> schema = RuntimeSchema.getSchema(clazz); 175 List<T> result = null; 176 try { 177 result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(data), schema); 178 } catch (IOException e) { 179 throw new RuntimeException("反序列化对象列表发生异常!",e); 180 } 181 return result; 182 } 183 private static <T> T unSerializeT(byte[] data, Class<T> cls) { 184 try { 185 T message = cls.newInstance(); 186 Schema<T> schema = getSchema(cls); 187 ProtostuffIOUtil.mergeFrom(data, message, schema); 188 return message; 189 } catch (Exception e) { 190 throw new IllegalStateException(e.getMessage(), e); 191 } 192 } 193 194 195 public static boolean isNullOrEmpty(Object obj) { 196 try { 197 if (obj == null) 198 return true; 199 if (obj instanceof CharSequence) { 200 return ((CharSequence) obj).length() == 0; 201 } 202 if (obj instanceof Collection) { 203 return ((Collection<?>) obj).isEmpty(); 204 } 205 if (obj instanceof Map) { 206 return ((Map<?, ?>) obj).isEmpty(); 207 } 208 if (obj instanceof Object[]) { 209 Object[] object = (Object[]) obj; 210 if (object.length == 0) { 211 return true; 212 } 213 boolean empty = true; 214 for (int i = 0; i < object.length; i++) { 215 if (!isNullOrEmpty(object[i])) { 216 empty = false; 217 break; 218 } 219 } 220 return empty; 221 } 222 return false; 223 } catch (Exception e) { 224 e.printStackTrace(); 225 return true; 226 } 227 228 } 229 230 231 @SuppressWarnings({ "serial" }) 232 public static class CustomWrapper implements Serializable{ 233 234 private Class<?> clazz; 235 236 private byte []data; 237 238 public CustomWrapper(){} 239 240 public CustomWrapper(Class<?> clazz,byte[] data){ 241 this.clazz=clazz; 242 this.data=data; 243 } 244 245 public byte[] getData() { 246 return data; 247 } 248 249 public void setData(byte[] data) { 250 this.data = data; 251 } 252 253 public Class<?> getClazz() { 254 return clazz; 255 } 256 257 public void setClazz(Class<?> clazz) { 258 this.clazz = clazz; 259 } 260 261 262 } 263 264 265 @SuppressWarnings({ "rawtypes", "serial", "unused" }) 266 public static class ValueWrapper implements Serializable{ 267 268 269 private Map mapValue; 270 271 private List listValue; 272 273 private Collection collectionValue; 274 275 private Iterable iterableValue; 276 277 private Set setValue; 278 279 private String stringValue; 280 281 private Byte byteValue; 282 283 private Short shortValue; 284 285 private Long longValue; 286 287 private Integer integerValue; 288 289 private Double doubleValue; 290 291 private Float floatValue; 292 293 private Character characterValue; 294 295 private Boolean booleanValue; 296 297 298 public ValueWrapper(){} 299 300 public ValueWrapper(Object data) throws IllegalArgumentException, IllegalAccessException { 301 if (data == null) { 302 return; 303 } 304 if (isNullOrEmpty(wrapperMap)) { 305 initFiledType(); 306 } 307 if (wrapperMap.containsKey(data.getClass())) { 308 Field f = wrapperMap.get(data.getClass()); 309 f.setAccessible(true); 310 f.set(this, data); 311 } 312 for (Class<?> clazz : wrapperMap.keySet()) { 313 if (!clazz.isAssignableFrom(data.getClass())) { 314 continue; 315 } 316 Field f = wrapperMap.get(clazz); 317 f.setAccessible(true); 318 f.set(this, data); 319 wrapperMap.put(data.getClass(), f); 320 return; 321 } 322 } 323 324 public static boolean isSpecialType(Class<?> clazz){ 325 if (isNullOrEmpty(wrapperMap)) { 326 initFiledType(); 327 } 328 if(unWrapperMap.containsKey(clazz)){ 329 return false; 330 } 331 if(wrapperMap.containsKey(clazz)){ 332 return true; 333 } 334 for (Class<?> clazzTmp : wrapperMap.keySet()) { 335 if (!clazzTmp.isAssignableFrom(clazz)) { 336 continue; 337 } 338 Field f = wrapperMap.get(clazzTmp); 339 f.setAccessible(true); 340 wrapperMap.put(clazz, f); 341 return true; 342 } 343 unWrapperMap.put(clazz, clazz); 344 return false; 345 } 346 private static void initFiledType() { 347 Field[] fields = ValueWrapper.class.getDeclaredFields(); 348 for (Field f : fields) { 349 wrapperMap.put(f.getType(), f); 350 } 351 } 352 353 public <T> T getValue() throws IllegalArgumentException, IllegalAccessException { 354 for (Class<?> clazz : wrapperMap.keySet()) { 355 T result = (T) wrapperMap.get(clazz).get(this); 356 if (isNullOrEmpty(result)) { 357 continue; 358 } 359 return result; 360 } 361 return null; 362 } 363 364 } 365 366 367}
测试图:
