JAVA RPC(二)序列化协议杂谈

      序列化和反序列化作为Java里一个较为基础的知识点,大家心里也有那么几句要说的,但我相信很多小伙伴掌握的也就是那么几句而已,如果再深究问一下Java如何实现序列化和反序列化的,就可能不知所措了!遥记当年也被问了这一个问题,自信满满的说了一大堆,什么是序列化、什么是反序列化、什么场景的时候才会用到等,然后面试官说:那你能说一下序列化和反序列化底层是如何实现的吗?一脸懵逼,然后回家等通知!
 

1、什么是序列化和反序列化

(1)Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程;

(2)序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。

(3)反序列化:客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

(4)本质上讲,序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态。

 

2、为什么需要序列化与反序列化

我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。

那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的!如何做到呢?这就需要Java序列化与反序列化了!

换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

总的来说可以归结为以下几点:

(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;
(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;
(3)通过序列化在进程间传递对象;

3、序列化算法一般会按步骤做如下事情:

(1)将对象实例相关的类元数据输出。
(2)递归地输出类的超类描述直到不再有超类。
(3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
(4)从上至下递归输出实例的数据

4、各种 Java 的序列化库的性能比较测试结果

  • 专门针对Java语言的:Kryo,FST等等
  • 跨语言的:Protostuff,ProtoBuf,Thrift,Avro,MsgPack等等

图片来源于网络,可以说明对原生序列化来讲,其他三方框架提供的序列化协议要快很多,所以我们做RPC技术选型的时候,序列化协议这块一定要摒弃原生序列化,去选择一款自己熟悉的序列化协议来传输IO流。下面选择做一个thrift序列化和原生序列化的对比结果。

 

原生序列化user类

package util.dto;

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private Integer integer;
    private String address;

    public User(String name, Integer integer, String address) {
        this.name = name;
        this.integer = integer;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getInteger() {
        return integer;
    }

    public void setInteger(Integer integer) {
        this.integer = integer;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

 

原生序列化工具类

 1 package util;
 2 
 3 import java.io.*;
 4 import java.util.Arrays;
 5 
 6 public class SerializeUtil {
 7 
 8     /** 序列化对象
 9      * @throws IOException */
10     public static byte[] serializeObject(Object object) throws IOException {
11         ByteArrayOutputStream saos = new ByteArrayOutputStream ();
12         ObjectOutputStream oos = new ObjectOutputStream(saos);
13         oos.writeObject(object);
14         oos.flush();
15         return saos.toByteArray();
16     }
17 
18     /** 反序列化对象
19      * @throws IOException
20      * @throws ClassNotFoundException */
21     public static Object deserializeObject(byte[] buf) throws IOException, ClassNotFoundException{
22         Object object=null;
23         ByteArrayInputStream sais=new ByteArrayInputStream(buf);
24         ObjectInputStream ois = new ObjectInputStream(sais);
25         object = ois.readObject();
26         return object;
27     }
28 }

 

由thrift脚本生成的User类

  1 /**
  2  * Autogenerated by Thrift Compiler (0.8.0)
  3  *
  4  * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
  5  *  @generated
  6  */
  7 package util.dtothrift;
  8 
  9 import org.apache.thrift.scheme.IScheme;
 10 import org.apache.thrift.scheme.SchemeFactory;
 11 import org.apache.thrift.scheme.StandardScheme;
 12 
 13 import org.apache.thrift.scheme.TupleScheme;
 14 import org.apache.thrift.protocol.TTupleProtocol;
 15 import java.util.List;
 16 import java.util.ArrayList;
 17 import java.util.Map;
 18 import java.util.HashMap;
 19 import java.util.EnumMap;
 20 import java.util.Set;
 21 import java.util.HashSet;
 22 import java.util.EnumSet;
 23 import java.util.Collections;
 24 import java.util.BitSet;
 25 import java.nio.ByteBuffer;
 26 import java.util.Arrays;
 27 import org.slf4j.Logger;
 28 import org.slf4j.LoggerFactory;
 29 
 30 public class User implements org.apache.thrift.TBase<User, User._Fields>, java.io.Serializable, Cloneable {
 31   private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("User");
 32 
 33   private static final org.apache.thrift.protocol.TField STR_FIELD_DESC = new org.apache.thrift.protocol.TField("str", org.apache.thrift.protocol.TType.STRING, (short)1);
 34   private static final org.apache.thrift.protocol.TField AGE_FIELD_DESC = new org.apache.thrift.protocol.TField("age", org.apache.thrift.protocol.TType.I32, (short)2);
 35   private static final org.apache.thrift.protocol.TField ADDRESS_FIELD_DESC = new org.apache.thrift.protocol.TField("address", org.apache.thrift.protocol.TType.STRING, (short)3);
 36 
 37   private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
 38   static {
 39     schemes.put(StandardScheme.class, new UserStandardSchemeFactory());
 40     schemes.put(TupleScheme.class, new UserTupleSchemeFactory());
 41   }
 42 
 43   public String str; // required
 44   public int age; // required
 45   public String address; // required
 46 
 47   /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
 48   public enum _Fields implements org.apache.thrift.TFieldIdEnum {
 49     STR((short)1, "str"),
 50     AGE((short)2, "age"),
 51     ADDRESS((short)3, "address");
 52 
 53     private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 54 
 55     static {
 56       for (_Fields field : EnumSet.allOf(_Fields.class)) {
 57         byName.put(field.getFieldName(), field);
 58       }
 59     }
 60 
 61     /**
 62      * Find the _Fields constant that matches fieldId, or null if its not found.
 63      */
 64     public static _Fields findByThriftId(int fieldId) {
 65       switch(fieldId) {
 66         case 1: // STR
 67           return STR;
 68         case 2: // AGE
 69           return AGE;
 70         case 3: // ADDRESS
 71           return ADDRESS;
 72         default:
 73           return null;
 74       }
 75     }
 76 
 77     /**
 78      * Find the _Fields constant that matches fieldId, throwing an exception
 79      * if it is not found.
 80      */
 81     public static _Fields findByThriftIdOrThrow(int fieldId) {
 82       _Fields fields = findByThriftId(fieldId);
 83       if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
 84       return fields;
 85     }
 86 
 87     /**
 88      * Find the _Fields constant that matches name, or null if its not found.
 89      */
 90     public static _Fields findByName(String name) {
 91       return byName.get(name);
 92     }
 93 
 94     private final short _thriftId;
 95     private final String _fieldName;
 96 
 97     _Fields(short thriftId, String fieldName) {
 98       _thriftId = thriftId;
 99       _fieldName = fieldName;
100     }
101 
102     public short getThriftFieldId() {
103       return _thriftId;
104     }
105 
106     public String getFieldName() {
107       return _fieldName;
108     }
109   }
110 
111   // isset id assignments
112   private static final int __AGE_ISSET_ID = 0;
113   private BitSet __isset_bit_vector = new BitSet(1);
114   public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
115   static {
116     Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
117     tmpMap.put(_Fields.STR, new org.apache.thrift.meta_data.FieldMetaData("str", org.apache.thrift.TFieldRequirementType.DEFAULT, 
118         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
119     tmpMap.put(_Fields.AGE, new org.apache.thrift.meta_data.FieldMetaData("age", org.apache.thrift.TFieldRequirementType.DEFAULT, 
120         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
121     tmpMap.put(_Fields.ADDRESS, new org.apache.thrift.meta_data.FieldMetaData("address", org.apache.thrift.TFieldRequirementType.DEFAULT, 
122         new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
123     metaDataMap = Collections.unmodifiableMap(tmpMap);
124     org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(User.class, metaDataMap);
125   }
126 
127   public User() {
128   }
129 
130   public User(
131     String str,
132     int age,
133     String address)
134   {
135     this();
136     this.str = str;
137     this.age = age;
138     setAgeIsSet(true);
139     this.address = address;
140   }
141 
142   /**
143    * Performs a deep copy on <i>other</i>.
144    */
145   public User(User other) {
146     __isset_bit_vector.clear();
147     __isset_bit_vector.or(other.__isset_bit_vector);
148     if (other.isSetStr()) {
149       this.str = other.str;
150     }
151     this.age = other.age;
152     if (other.isSetAddress()) {
153       this.address = other.address;
154     }
155   }
156 
157   public User deepCopy() {
158     return new User(this);
159   }
160 
161   @Override
162   public void clear() {
163     this.str = null;
164     setAgeIsSet(false);
165     this.age = 0;
166     this.address = null;
167   }
168 
169   public String getStr() {
170     return this.str;
171   }
172 
173   public User setStr(String str) {
174     this.str = str;
175     return this;
176   }
177 
178   public void unsetStr() {
179     this.str = null;
180   }
181 
182   /** Returns true if field str is set (has been assigned a value) and false otherwise */
183   public boolean isSetStr() {
184     return this.str != null;
185   }
186 
187   public void setStrIsSet(boolean value) {
188     if (!value) {
189       this.str = null;
190     }
191   }
192 
193   public int getAge() {
194     return this.age;
195   }
196 
197   public User setAge(int age) {
198     this.age = age;
199     setAgeIsSet(true);
200     return this;
201   }
202 
203   public void unsetAge() {
204     __isset_bit_vector.clear(__AGE_ISSET_ID);
205   }
206 
207   /** Returns true if field age is set (has been assigned a value) and false otherwise */
208   public boolean isSetAge() {
209     return __isset_bit_vector.get(__AGE_ISSET_ID);
210   }
211 
212   public void setAgeIsSet(boolean value) {
213     __isset_bit_vector.set(__AGE_ISSET_ID, value);
214   }
215 
216   public String getAddress() {
217     return this.address;
218   }
219 
220   public User setAddress(String address) {
221     this.address = address;
222     return this;
223   }
224 
225   public void unsetAddress() {
226     this.address = null;
227   }
228 
229   /** Returns true if field address is set (has been assigned a value) and false otherwise */
230   public boolean isSetAddress() {
231     return this.address != null;
232   }
233 
234   public void setAddressIsSet(boolean value) {
235     if (!value) {
236       this.address = null;
237     }
238   }
239 
240   public void setFieldValue(_Fields field, Object value) {
241     switch (field) {
242     case STR:
243       if (value == null) {
244         unsetStr();
245       } else {
246         setStr((String)value);
247       }
248       break;
249 
250     case AGE:
251       if (value == null) {
252         unsetAge();
253       } else {
254         setAge((Integer)value);
255       }
256       break;
257 
258     case ADDRESS:
259       if (value == null) {
260         unsetAddress();
261       } else {
262         setAddress((String)value);
263       }
264       break;
265 
266     }
267   }
268 
269   public Object getFieldValue(_Fields field) {
270     switch (field) {
271     case STR:
272       return getStr();
273 
274     case AGE:
275       return Integer.valueOf(getAge());
276 
277     case ADDRESS:
278       return getAddress();
279 
280     }
281     throw new IllegalStateException();
282   }
283 
284   /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
285   public boolean isSet(_Fields field) {
286     if (field == null) {
287       throw new IllegalArgumentException();
288     }
289 
290     switch (field) {
291     case STR:
292       return isSetStr();
293     case AGE:
294       return isSetAge();
295     case ADDRESS:
296       return isSetAddress();
297     }
298     throw new IllegalStateException();
299   }
300 
301   @Override
302   public boolean equals(Object that) {
303     if (that == null)
304       return false;
305     if (that instanceof User)
306       return this.equals((User)that);
307     return false;
308   }
309 
310   public boolean equals(User that) {
311     if (that == null)
312       return false;
313 
314     boolean this_present_str = true && this.isSetStr();
315     boolean that_present_str = true && that.isSetStr();
316     if (this_present_str || that_present_str) {
317       if (!(this_present_str && that_present_str))
318         return false;
319       if (!this.str.equals(that.str))
320         return false;
321     }
322 
323     boolean this_present_age = true;
324     boolean that_present_age = true;
325     if (this_present_age || that_present_age) {
326       if (!(this_present_age && that_present_age))
327         return false;
328       if (this.age != that.age)
329         return false;
330     }
331 
332     boolean this_present_address = true && this.isSetAddress();
333     boolean that_present_address = true && that.isSetAddress();
334     if (this_present_address || that_present_address) {
335       if (!(this_present_address && that_present_address))
336         return false;
337       if (!this.address.equals(that.address))
338         return false;
339     }
340 
341     return true;
342   }
343 
344   @Override
345   public int hashCode() {
346     return 0;
347   }
348 
349   public int compareTo(User other) {
350     if (!getClass().equals(other.getClass())) {
351       return getClass().getName().compareTo(other.getClass().getName());
352     }
353 
354     int lastComparison = 0;
355     User typedOther = (User)other;
356 
357     lastComparison = Boolean.valueOf(isSetStr()).compareTo(typedOther.isSetStr());
358     if (lastComparison != 0) {
359       return lastComparison;
360     }
361     if (isSetStr()) {
362       lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.str, typedOther.str);
363       if (lastComparison != 0) {
364         return lastComparison;
365       }
366     }
367     lastComparison = Boolean.valueOf(isSetAge()).compareTo(typedOther.isSetAge());
368     if (lastComparison != 0) {
369       return lastComparison;
370     }
371     if (isSetAge()) {
372       lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.age, typedOther.age);
373       if (lastComparison != 0) {
374         return lastComparison;
375       }
376     }
377     lastComparison = Boolean.valueOf(isSetAddress()).compareTo(typedOther.isSetAddress());
378     if (lastComparison != 0) {
379       return lastComparison;
380     }
381     if (isSetAddress()) {
382       lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.address, typedOther.address);
383       if (lastComparison != 0) {
384         return lastComparison;
385       }
386     }
387     return 0;
388   }
389 
390   public _Fields fieldForId(int fieldId) {
391     return _Fields.findByThriftId(fieldId);
392   }
393 
394   public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
395     schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
396   }
397 
398   public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
399     schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
400   }
401 
402   @Override
403   public String toString() {
404     StringBuilder sb = new StringBuilder("User(");
405     boolean first = true;
406 
407     sb.append("str:");
408     if (this.str == null) {
409       sb.append("null");
410     } else {
411       sb.append(this.str);
412     }
413     first = false;
414     if (!first) sb.append(", ");
415     sb.append("age:");
416     sb.append(this.age);
417     first = false;
418     if (!first) sb.append(", ");
419     sb.append("address:");
420     if (this.address == null) {
421       sb.append("null");
422     } else {
423       sb.append(this.address);
424     }
425     first = false;
426     sb.append(")");
427     return sb.toString();
428   }
429 
430   public void validate() throws org.apache.thrift.TException {
431     // check for required fields
432   }
433 
434   private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
435     try {
436       write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
437     } catch (org.apache.thrift.TException te) {
438       throw new java.io.IOException(te);
439     }
440   }
441 
442   private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
443     try {
444       // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
445       __isset_bit_vector = new BitSet(1);
446       read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
447     } catch (org.apache.thrift.TException te) {
448       throw new java.io.IOException(te);
449     }
450   }
451 
452   private static class UserStandardSchemeFactory implements SchemeFactory {
453     public UserStandardScheme getScheme() {
454       return new UserStandardScheme();
455     }
456   }
457 
458   private static class UserStandardScheme extends StandardScheme<User> {
459 
460     public void read(org.apache.thrift.protocol.TProtocol iprot, User struct) throws org.apache.thrift.TException {
461       org.apache.thrift.protocol.TField schemeField;
462       iprot.readStructBegin();
463       while (true)
464       {
465         schemeField = iprot.readFieldBegin();
466         if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
467           break;
468         }
469         switch (schemeField.id) {
470           case 1: // STR
471             if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
472               struct.str = iprot.readString();
473               struct.setStrIsSet(true);
474             } else { 
475               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
476             }
477             break;
478           case 2: // AGE
479             if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
480               struct.age = iprot.readI32();
481               struct.setAgeIsSet(true);
482             } else { 
483               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
484             }
485             break;
486           case 3: // ADDRESS
487             if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
488               struct.address = iprot.readString();
489               struct.setAddressIsSet(true);
490             } else { 
491               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
492             }
493             break;
494           default:
495             org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
496         }
497         iprot.readFieldEnd();
498       }
499       iprot.readStructEnd();
500 
501       // check for required fields of primitive type, which can't be checked in the validate method
502       struct.validate();
503     }
504 
505     public void write(org.apache.thrift.protocol.TProtocol oprot, User struct) throws org.apache.thrift.TException {
506       struct.validate();
507 
508       oprot.writeStructBegin(STRUCT_DESC);
509       if (struct.str != null) {
510         oprot.writeFieldBegin(STR_FIELD_DESC);
511         oprot.writeString(struct.str);
512         oprot.writeFieldEnd();
513       }
514       oprot.writeFieldBegin(AGE_FIELD_DESC);
515       oprot.writeI32(struct.age);
516       oprot.writeFieldEnd();
517       if (struct.address != null) {
518         oprot.writeFieldBegin(ADDRESS_FIELD_DESC);
519         oprot.writeString(struct.address);
520         oprot.writeFieldEnd();
521       }
522       oprot.writeFieldStop();
523       oprot.writeStructEnd();
524     }
525 
526   }
527 
528   private static class UserTupleSchemeFactory implements SchemeFactory {
529     public UserTupleScheme getScheme() {
530       return new UserTupleScheme();
531     }
532   }
533 
534   private static class UserTupleScheme extends TupleScheme<User> {
535 
536     @Override
537     public void write(org.apache.thrift.protocol.TProtocol prot, User struct) throws org.apache.thrift.TException {
538       TTupleProtocol oprot = (TTupleProtocol) prot;
539       BitSet optionals = new BitSet();
540       if (struct.isSetStr()) {
541         optionals.set(0);
542       }
543       if (struct.isSetAge()) {
544         optionals.set(1);
545       }
546       if (struct.isSetAddress()) {
547         optionals.set(2);
548       }
549       oprot.writeBitSet(optionals, 3);
550       if (struct.isSetStr()) {
551         oprot.writeString(struct.str);
552       }
553       if (struct.isSetAge()) {
554         oprot.writeI32(struct.age);
555       }
556       if (struct.isSetAddress()) {
557         oprot.writeString(struct.address);
558       }
559     }
560 
561     @Override
562     public void read(org.apache.thrift.protocol.TProtocol prot, User struct) throws org.apache.thrift.TException {
563       TTupleProtocol iprot = (TTupleProtocol) prot;
564       BitSet incoming = iprot.readBitSet(3);
565       if (incoming.get(0)) {
566         struct.str = iprot.readString();
567         struct.setStrIsSet(true);
568       }
569       if (incoming.get(1)) {
570         struct.age = iprot.readI32();
571         struct.setAgeIsSet(true);
572       }
573       if (incoming.get(2)) {
574         struct.address = iprot.readString();
575         struct.setAddressIsSet(true);
576       }
577     }
578   }
579 
580 }

 

测试类

 1 package util;
 2 
 3 import org.apache.thrift.TException;
 4 import org.apache.thrift.protocol.TBinaryProtocol;
 5 import org.apache.thrift.transport.TIOStreamTransport;
 6 import org.apache.thrift.transport.TSocket;
 7 import org.apache.thrift.transport.TTransport;
 8 import org.slf4j.Logger;
 9 import org.slf4j.LoggerFactory;
10 import util.dto.User;
11 
12 import java.io.ByteArrayInputStream;
13 import java.io.ByteArrayOutputStream;
14 import java.io.IOException;
15 import java.util.Arrays;
16 
17 public class SerializeTest {
18 
19     private final static Logger logger = LoggerFactory.getLogger ( SerializeTest.class );
20 
21     public static void main(String[] args) throws IOException, ClassNotFoundException, TException {
22 
23         long a = System.currentTimeMillis ();
24         for (int i = 0; i < 100000; i++) {
25             User user = new User("姓名"+i,i,"北京市海淀区中关村大厦"+i);
26             byte[] b = SerializeUtil.serializeObject ( user );
27             //System.out.println (Arrays.toString ( b ));
28             User user1 = (User) SerializeUtil.deserializeObject ( b );
29         }
30         System.out.println (System.currentTimeMillis ()-a);
31 
32         long b = System.currentTimeMillis ();
33 
34         for (int i = 0; i < 100000; i++) {
35             util.dtothrift.User user = new util.dtothrift.User("姓名"+i,i,"北京市海淀区中关村大厦"+i);
36             ByteArrayOutputStream out = new ByteArrayOutputStream();
37             TTransport transport = new TIOStreamTransport (out);
38             TBinaryProtocol tp = new TBinaryProtocol(transport);
39             try {
40                 user.write(tp);
41             } catch (TException e) {
42                 e.printStackTrace();
43             }
44             byte[] bytes = out.toByteArray();
45             //System.out.println ( Arrays.toString ( bytes ));
46             util.dtothrift.User user1 = new util.dtothrift.User();
47 
48             ByteArrayInputStream bis = new ByteArrayInputStream (  bytes);
49             TTransport transport1 = new TIOStreamTransport(bis);
50             TBinaryProtocol tp1 = new TBinaryProtocol(transport1);
51             user1.read (tp1);
52         }
53         System.out.println (System.currentTimeMillis ()-b);
54     }
55 
56 }

 

10万次序列化和反序列化的结果对比

 

由上图可以看出,采用facebook的序列化协议要比原生jdk序列化协议在10万次序列化和反序列化操作中的时间快很多,并且thrift没有原生序列化的那么多的要求,我们来看看原生序列化和thrift序列化的输入结果都是什么,打开 System.out.println ( Arrays.toString ( bytes ))代码后

jdk 输出流

[-84, -19, 0, 5, 115, 114, 0, 13, 117, 116, 105, 108, 46, 100, 116, 111, 46, 85, 115, 101, 114, -45, 124, 21, -36, 14, -39, -44, 35, 2, 0, 3, 76, 0, 7, 97, 100, 100, 114, 101, 115, 115, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 7, 105, 110, 116, 101, 103, 101, 114, 116, 0, 19, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 73, 110, 116, 101, 103, 101, 114, 59, 76, 0, 4, 110, 97, 109, 101, 113, 0, 126, 0, 1, 120, 112, 116, 0, 34, -27, -116, -105, -28, -70, -84, -27, -72, -126, -26, -75, -73, -26, -73, -128, -27, -116, -70, -28, -72, -83, -27, -123, -77, -26, -99, -111, -27, -92, -89, -27, -114, -90, 48, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 0, 0, 116, 0, 7, -27, -89, -109, -27, -112, -115, 48]

thrift输出流

[11, 0, 1, 0, 0, 0, 7, -27, -89, -109, -27, -112, -115, 48, 8, 0, 2, 0, 0, 0, 0, 11, 0, 3, 0, 0, 0, 34, -27, -116, -105, -28, -70, -84, -27, -72, -126, -26, -75, -73, -26, -73, -128, -27, -116, -70, -28, -72, -83, -27, -123, -77, -26, -99, -111, -27, -92, -89, -27, -114, -90, 48, 0]

由此可以看出jdk的输出流比thrift的输出流多很多,因为jdk原生序列化对方法栈信息,类信息等做了详细的记录,其实这些信息对于RPC来说不是传输必要参数,所以精简序列化IO流大小在传输中十分关键

本章对序列化进行了简单的概述,大家可以针对我的上面代码进行测试。

 

高级java交流群:825199617

欢迎热爱源码志同道合的朋友加入。

koalas rpc源码地址https://gitee.com/a1234567891/koalas-rpc

posted on 2018-10-31 12:32  张玉龙  阅读(2144)  评论(0编辑  收藏  举报