JAVA基础4---序列化和反序列化深入整理(Hessian序列化)

一、Hessian序列化用法

1、maven依赖

<dependency>
      <groupId>com.caucho</groupId>
      <artifactId>hessian</artifactId>
      <version>4.0.38</version>
</dependency>

2、序列化和反序列化

 1 /** Hessian序列化 */
 2     public static byte[] hessianSerialize(Object object){
 3         Hessian2Output oo = null;
 4         byte[] result = null;
 5         try {
 6             ByteArrayOutputStream bos = new ByteArrayOutputStream();
 7             oo = new Hessian2Output(bos);
 8             oo.writeObject(object);
 9             oo.flush();
10             result = bos.toByteArray();
11         } catch (IOException e) {
12             e.printStackTrace();
13         }
14         return result;
15     }
16 
17     /** Hessian反序列化 */
18     public static Object hessianSerializeToObj(byte[] bytes){
19         Object result = null;
20         try{
21             ByteArrayInputStream is = new ByteArrayInputStream(bytes);
22             Hessian2Input input = new Hessian2Input(is);
23             result = input.readObject();
24         }catch (Exception e){
25             e.printStackTrace();
26         }
27         return result;
28     }

Hessian的序列化和反序列化分别是依靠Hessian2Output和Hessian2Input来实现,首先是定义一个二进制字节流对象ByteArrayOutputStream和ByteArrayOutputStream对象,分别通过对应的Hessian对象进行二进制流的读写操作。

所以说核心逻辑主要在于Hessian2Output的writeObejct方法和Hessian2Input的readObject方法。 

二、Hessian序列化源码解析

2.1、序列化源码解析

1、首先分析Hessian2Output的初始化过程,源码如下:

 1 /** 输出字节流对象*/
 2     protected OutputStream _os;
 3 
 4     public Hessian2Output(OutputStream os)
 5     {
 6         init(os);
 7     }
 8 
 9     /** 初始化*/
10     public void init(OutputStream os)
11     {
12         reset();
13         _os = os;
14     }
15 
16     /** 重置所有的指针和引用*/
17     public void reset()
18     {
19         if (_refs != null) {
20             _refs.clear();
21             _refCount = 0;
22         }
23 
24         _classRefs.clear();
25         _typeRefs = null;
26         _offset = 0;
27         _isPacket = false;
28         _isUnshared = false;
29     }

Hessian2Output的内部有一个OutputStream属性,用于将对象序列化后的字节流写入到此对象中,构造方法主要是重置了所有和序列化相关的熟悉,并且给字节流对象进行初始化

2、writeObejct方法解析

public void writeObject(Object object)throws IOException
    {
        /** 1.如果对象为空,则写入空对象 */
        if (object == null) {
            writeNull();
            return;
        }
        /** 2.根据对象的Class来获取序列化器 */
        Serializer serializer = findSerializerFactory().getObjectSerializer(object.getClass());
        /** 3.调用序列化器的writeObject进行对象序列化 */
        serializer.writeObject(object, this);
    }

方法比较简单,如果对象为空就写入空数据;如果对象不为空,那么就根据对象的Class信息构造一个指定类型的序列化器对象,然后直接调用序列化器的writeObejct方法进行序列化。

2.1、当对象为空时

 1     public final static int SIZE = 8 * 1024;
        /** 字节数组缓存 */
 2     private final byte []_buffer = new byte[SIZE];
3 /** 字节数组偏移量 */ 4 private int _offset; 5 6 /** 写入空对象 */ 7 public void writeNull() throws IOException 8 { 9 int offset = _offset; 10 byte []buffer = _buffer; 11 12 if (SIZE <= offset + 16) { 13 /** 如果字节数组缓存不足,则将缓存数据写入到OutputStream中并清除缓存*/ 14 flushBuffer(); 15 offset = _offset; 16 } 17 /** 写入字符串N表示当前的对象为空对象 */ 18 buffer[offset++] = 'N'; 19 /** 更新偏移量*/ 20 _offset = offset; 21 } 22 23 /** 清除缓存,并将缓存数据写入输出字节流中*/ 24 public final void flushBuffer() 25 throws IOException 26 { 27 int offset = _offset; 28 OutputStream os = _os; 29 30 if (! _isPacket && offset > 0) { 31 _offset = 0; 32 if (os != null) 33 os.write(_buffer, 0, offset); 34 } 35 else if (_isPacket && offset > 4) { 36 int len = offset - 4; 37 38 _buffer[0] |= (byte) 0x80; 39 _buffer[1] = (byte) (0x7e); 40 _buffer[2] = (byte) (len >> 8); 41 _buffer[3] = (byte) (len); 42 _offset = 4; 43 44 if (os != null) 45 os.write(_buffer, 0, offset); 46 47 _buffer[0] = (byte) 0x00; 48 _buffer[1] = (byte) 0x56; 49 _buffer[2] = (byte) 0x56; 50 _buffer[3] = (byte) 0x56; 51 } 52 }

writeNull方法逻辑不复杂,主要就是在字节数组中写入字符串"N"即可。这里可以看出Hessian2Output对象内部有一个字节数组缓存_buffer对象和一个数组写入偏移量_offset变量。

字节数组缓存大小为8 * 1024个字节相当于 8K的容量,序列化的时候会先将序列化的字节流写入缓存中,当缓存容量不足的时在调用flushbuffer方法将缓冲区的数据写入字节流对象中,并清除缓冲区。

2.2、当对象不为空时

当对象不为空时,进行序列化的时候需要根据对象类型进行不同的序列化方式,比如String有String的序列化方式,List有List的序列化方式,而且通常还有用户自定义的实体类,还需要有对象的序列化方式。

对象序列化的接口为Serializer,定义如下:

1 public interface Serializer {
2         public void writeObject(Object obj, AbstractHessianOutput out)throws IOException;
3     }

具体的实现类比较多,针对不同的类型有不同的实现子类,

2.2.1、基本数据类型序列化

对于常用的基本数据类型及对应的数组类型,Hessian提供了基本数据类型序列化器BasicSerializer,在ContextSerializerFactory类中进行了初始化注册,代码如下:

 1 addBasic(void.class, "void", BasicSerializer.NULL);
 2 
 3     addBasic(Boolean.class, "boolean", BasicSerializer.BOOLEAN);
 4     addBasic(Byte.class, "byte", BasicSerializer.BYTE);
 5     addBasic(Short.class, "short", BasicSerializer.SHORT);
 6     addBasic(Integer.class, "int", BasicSerializer.INTEGER);
 7     addBasic(Long.class, "long", BasicSerializer.LONG);
 8     addBasic(Float.class, "float", BasicSerializer.FLOAT);
 9     addBasic(Double.class, "double", BasicSerializer.DOUBLE);
10     addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT);
11     addBasic(String.class, "string", BasicSerializer.STRING);
12     addBasic(Object.class, "object", BasicSerializer.OBJECT);
13     addBasic(java.util.Date.class, "date", BasicSerializer.DATE);
14 
15     addBasic(boolean.class, "boolean", BasicSerializer.BOOLEAN);
16     addBasic(byte.class, "byte", BasicSerializer.BYTE);
17     addBasic(short.class, "short", BasicSerializer.SHORT);
18     addBasic(int.class, "int", BasicSerializer.INTEGER);
19     addBasic(long.class, "long", BasicSerializer.LONG);
20     addBasic(float.class, "float", BasicSerializer.FLOAT);
21     addBasic(double.class, "double", BasicSerializer.DOUBLE);
22     addBasic(char.class, "char", BasicSerializer.CHARACTER);
23 
24     addBasic(boolean[].class, "[boolean", BasicSerializer.BOOLEAN_ARRAY);
25     addBasic(byte[].class, "[byte", BasicSerializer.BYTE_ARRAY);
26     _staticSerializerMap.put(byte[].class.getName(), ByteArraySerializer.SER);
27     addBasic(short[].class, "[short", BasicSerializer.SHORT_ARRAY);
28     addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY);
29     addBasic(long[].class, "[long", BasicSerializer.LONG_ARRAY);
30     addBasic(float[].class, "[float", BasicSerializer.FLOAT_ARRAY);
31     addBasic(double[].class, "[double", BasicSerializer.DOUBLE_ARRAY);
32     addBasic(char[].class, "[char", BasicSerializer.CHARACTER_ARRAY);
33     addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY);
34     addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY);

虽然基本数据类型都是通过BasicSerializer进行序列化,但是不同的类型都是有不同的type的,BasicSerializer根据不同的type进行不同的序列化逻辑处理。具体的序列化逻辑如下:

  1 /** 基本数据类型*/
  2     public void writeObject(Object obj, AbstractHessianOutput out)
  3             throws IOException
  4     {
  5         switch (_code) {
  6             case BOOLEAN:
  7                 out.writeBoolean(((Boolean) obj).booleanValue());
  8                 break;
  9 
 10             case BYTE:
 11             case SHORT:
 12             case INTEGER:
 13                 out.writeInt(((Number) obj).intValue());
 14                 break;
 15 
 16             case LONG:
 17                 out.writeLong(((Number) obj).longValue());
 18                 break;
 19 
 20             case FLOAT:
 21             case DOUBLE:
 22                 out.writeDouble(((Number) obj).doubleValue());
 23                 break;
 24 
 25             case CHARACTER:
 26             case CHARACTER_OBJECT:
 27                 out.writeString(String.valueOf(obj));
 28                 break;
 29 
 30             case STRING:
 31                 out.writeString((String) obj);
 32                 break;
 33 
 34             case STRING_BUILDER:
 35                 out.writeString(((StringBuilder) obj).toString());
 36                 break;
 37 
 38             case DATE:
 39                 out.writeUTCDate(((Date) obj).getTime());
 40                 break;
 41 
 42             case BOOLEAN_ARRAY:
 43             {
 44                 if (out.addRef(obj))
 45                     return;
 46 
 47                 boolean []data = (boolean []) obj;
 48                 boolean hasEnd = out.writeListBegin(data.length, "[boolean");
 49                 for (int i = 0; i < data.length; i++)
 50                     out.writeBoolean(data[i]);
 51 
 52                 if (hasEnd)
 53                     out.writeListEnd();
 54 
 55                 break;
 56             }
 57 
 58             case BYTE_ARRAY:
 59             {
 60                 byte []data = (byte []) obj;
 61                 out.writeBytes(data, 0, data.length);
 62                 break;
 63             }
 64 
 65             case SHORT_ARRAY:
 66             {
 67                 if (out.addRef(obj))
 68                     return;
 69 
 70                 short []data = (short []) obj;
 71                 boolean hasEnd = out.writeListBegin(data.length, "[short");
 72 
 73                 for (int i = 0; i < data.length; i++)
 74                     out.writeInt(data[i]);
 75 
 76                 if (hasEnd)
 77                     out.writeListEnd();
 78                 break;
 79             }
 80 
 81             case INTEGER_ARRAY:
 82             {
 83                 if (out.addRef(obj))
 84                     return;
 85 
 86                 int []data = (int []) obj;
 87 
 88                 boolean hasEnd = out.writeListBegin(data.length, "[int");
 89 
 90                 for (int i = 0; i < data.length; i++)
 91                     out.writeInt(data[i]);
 92 
 93                 if (hasEnd)
 94                     out.writeListEnd();
 95 
 96                 break;
 97             }
 98 
 99             case LONG_ARRAY:
100             {
101                 if (out.addRef(obj))
102                     return;
103 
104                 long []data = (long []) obj;
105 
106                 boolean hasEnd = out.writeListBegin(data.length, "[long");
107 
108                 for (int i = 0; i < data.length; i++)
109                     out.writeLong(data[i]);
110 
111                 if (hasEnd)
112                     out.writeListEnd();
113                 break;
114             }
115 
116             case FLOAT_ARRAY:
117             {
118                 if (out.addRef(obj))
119                     return;
120 
121                 float []data = (float []) obj;
122 
123                 boolean hasEnd = out.writeListBegin(data.length, "[float");
124 
125                 for (int i = 0; i < data.length; i++)
126                     out.writeDouble(data[i]);
127 
128                 if (hasEnd)
129                     out.writeListEnd();
130                 break;
131             }
132 
133             case DOUBLE_ARRAY:
134             {
135                 if (out.addRef(obj))
136                     return;
137 
138                 double []data = (double []) obj;
139                 boolean hasEnd = out.writeListBegin(data.length, "[double");
140 
141                 for (int i = 0; i < data.length; i++)
142                     out.writeDouble(data[i]);
143 
144                 if (hasEnd)
145                     out.writeListEnd();
146                 break;
147             }
148 
149             case STRING_ARRAY:
150             {
151                 if (out.addRef(obj))
152                     return;
153 
154                 String []data = (String []) obj;
155 
156                 boolean hasEnd = out.writeListBegin(data.length, "[string");
157 
158                 for (int i = 0; i < data.length; i++) {
159                     out.writeString(data[i]);
160                 }
161 
162                 if (hasEnd)
163                     out.writeListEnd();
164                 break;
165             }
166 
167             case CHARACTER_ARRAY:
168             {
169                 char []data = (char []) obj;
170                 out.writeString(data, 0, data.length);
171                 break;
172             }
173 
174             case OBJECT_ARRAY:
175             {
176                 if (out.addRef(obj))
177                     return;
178 
179                 Object []data = (Object []) obj;
180 
181                 boolean hasEnd = out.writeListBegin(data.length, "[object");
182 
183                 for (int i = 0; i < data.length; i++) {
184                     out.writeObject(data[i]);
185                 }
186 
187                 if (hasEnd)
188                     out.writeListEnd();
189                 break;
190             }
191 
192             case NULL:
193                 out.writeNull();
194                 break;
195 
196             case OBJECT:
197                 ObjectHandleSerializer.SER.writeObject(obj, out);
198                 break;
199 
200             case BYTE_HANDLE:
201                 out.writeObject(new ByteHandle((Byte) obj));
202                 break;
203 
204             case SHORT_HANDLE:
205                 out.writeObject(new ShortHandle((Short) obj));
206                 break;
207 
208             case FLOAT_HANDLE:
209                 out.writeObject(new FloatHandle((Float) obj));
210                 break;
211 
212             default:
213                 throw new RuntimeException(_code + " unknown code for " + obj.getClass());
214         }
215     }

逻辑比较清晰,根据类型调用对应的write方法,如果是数组类型会在write数据前后分别调用writeListBegin和writeListEnd方法表示写入数组的开始和结束标记。

如字符串的序列化方法writeString源码如下:

 1 /** 序列化字符串*/
 2     public void writeString(String value)throws IOException
 3     {
 4         int offset = _offset;
 5         byte []buffer = _buffer;
 6 
 7         /** 缓冲区满了则写入流对象并清理缓存*/
 8         if (SIZE <= offset + 16) {
 9             flushBuffer();
10             offset = _offset;
11         }
12 
13         /** 如果值为空则写入'N'标记*/
14         if (value == null) {
15             buffer[offset++] = (byte) 'N';
16             _offset = offset;
17         }
18         else {
19             int length = value.length();
20             int strOffset = 0;
21             /** 如果字符串长度大于32K则拆分成多个32K大小的字符串进行写入 */
22             while (length > 0x8000) {
23                 int sublen = 0x8000;
24                 offset = _offset;
25                 if (SIZE <= offset + 16) {
26                     flushBuffer();
27                     offset = _offset;
28                 }
29 
30                 // chunk can't end in high surrogate
31                 char tail = value.charAt(strOffset + sublen - 1);
32 
33                 if (0xd800 <= tail && tail <= 0xdbff)
34                     sublen--;
35 
36                 /** 依次写入字符串标记'R' 长度占用字节数 实际长度值*/
37                 buffer[offset + 0] = (byte) BC_STRING_CHUNK;
38                 buffer[offset + 1] = (byte) (sublen >> 8);
39                 buffer[offset + 2] = (byte) (sublen);
40 
41                 _offset = offset + 3;
42                 /** 写入字符串的具体数据 */
43                 printString(value, strOffset, sublen);
44 
45                 length -= sublen;
46                 strOffset += sublen;
47             }
48 
49             offset = _offset;
50 
51             if (SIZE <= offset + 16) {
52                 flushBuffer();
53                 offset = _offset;
54             }
55 
56             if (length <= STRING_DIRECT_MAX) {
57                 buffer[offset++] = (byte) (BC_STRING_DIRECT + length);
58             }
59             else if (length <= STRING_SHORT_MAX) {
60                 buffer[offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
61                 buffer[offset++] = (byte) (length);
62             }
63             else {
64                 buffer[offset++] = (byte) ('S');
65                 buffer[offset++] = (byte) (length >> 8);
66                 buffer[offset++] = (byte) (length);
67             }
68 
69             _offset = offset;
70 
71             printString(value, strOffset, length);
72         }
73     }

写入字符串时会先写入标记,如果字符串过长会进行拆分成多个子字符串,子字符串写入标记为"R",非子字符串会写入字符串标记"S",并且会在标记后面写入字符串的长度,最终才会窒息printString方法将字符串数据写入字节数组中。

printString方法的逻辑就是遍历字符串的每一位,依次将字符串的每个字符写入字节数组中。源码如下:

 1 public void printString(String v, int strOffset, int length)throws IOException
 2     {
 3         int offset = _offset;
 4         byte []buffer = _buffer;
 5 
 6         for (int i = 0; i < length; i++) {
 7             if (SIZE <= offset + 16) {
 8                 _offset = offset;
 9                 flushBuffer();
10                 offset = _offset;
11             }
12 
13             char ch = v.charAt(i + strOffset);
14 
15             if (ch < 0x80)
16                 buffer[offset++] = (byte) (ch);
17             else if (ch < 0x800) {
18                 buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
19                 buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
20             }
21             else {
22                 buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
23                 buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
24                 buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
25             }
26         }
27         _offset = offset;
28     }

其他基本数据类型的写入逻辑基本上和字符串的写入逻辑一致,都是在写入数据之前先写入标记,然后直接写入数据,比如Long类型就会写入标记"L",Double类型就写入"D", Int类型就写入"I"。

可以看出相比于JDK的序列化方式,在数据类型上来说Hessian的序列化就会比JDK的序列化写入的数据量要小很多。Hessian将基本数据类型仅仅用一个字符来表示,而JDK序列化会将类的全路径序列化。

如String类型的序列化,Hessian序列化字符串类型仅仅写入标记"S",而JDK序列化需要写入类路径"java.lang.String"

2.2.2、自定义数据类型序列化

自定义数据类型的序列化是通过UnsafeSerializer进行的序列化,源码如下:

 1 public void writeObject(Object obj, AbstractHessianOutput out)throws IOException
 2     {
 3         if (out.addRef(obj)) {
 4             return;
 5         }
 6 
 7         Class<?> cl = obj.getClass();
 8         /** 写入Object类型开始标记 将类名存入Map中,并记录该类的引用次数 */
 9         int ref = out.writeObjectBegin(cl.getName());
10 
11         /** 如果引用次数大于0则表示已经被引用过*/
12         if (ref >= 0) {
13             /** 直接写入实例 */
14             writeInstance(obj, out);
15         }
16         /** 值为-1表示第一次引用 */
17         else if (ref == -1) {
18             /** 写入类的定义,依次写入属性个数和所有属性的名称 */
19             writeDefinition20(out);
20             /** 写入类的名称 */
21             out.writeObjectBegin(cl.getName());
22             /** 写入实例 */
23             writeInstance(obj, out);
24         }
25         else {
26             writeObject10(obj, out);
27         }
28     }

主要逻辑为先获取Class的引用次数,如果Class已经引用过了则不需要重新解析,直接写入对象即可;如果Class没有引用过则先写入类的定义,包括属性的个数和依次写入所有属性的名称。然后在写入类的名称,最后再执行writeInstance方法写入实例对象。

writeDefinition20方法源码如下:

/** 写入类的定义*/
    private void writeDefinition20(AbstractHessianOutput out)throws IOException
    {
        /** 写入类的属性个数*/
        out.writeClassFieldLength(_fields.length);
        /** 依次写入属性的名称*/
        for (int i = 0; i < _fields.length; i++) {
            Field field = _fields[i];
            out.writeString(field.getName());
        }
    }

 writeObjectBegin方法源码如下:

 1 /** 开始写入对象*/
 2     public int writeObjectBegin(String type)throws IOException
 3     {
 4         //获取类的引用次数
 5         int newRef = _classRefs.size();
 6         int ref = _classRefs.put(type, newRef, false);
 7         if (newRef != ref) {
 8             if (SIZE < _offset + 32)
 9                 flushBuffer();
10 
11             if (ref <= OBJECT_DIRECT_MAX) {
12                 _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
13             }
14             else {
15                 //写入类的引用次数
16                 _buffer[_offset++] = (byte) 'O';
17                 writeInt(ref);
18             }
19 
20             return ref;
21         }
22         else {
23             if (SIZE < _offset + 32)
24                 flushBuffer();
25 
26             _buffer[_offset++] = (byte) 'C';
27 
28             writeString(type);
29 
30             return -1;
31         }
32     }

writeInstance方法源码如下:

 1 /** 写入对象实例 */
 2     final public void writeInstance(Object obj, AbstractHessianOutput out)throws IOException
 3     {
 4         try {
 5             /** 获取所有属性序列化器对象 */
 6             FieldSerializer []fieldSerializers = _fieldSerializers;
 7             int length = fieldSerializers.length;
 8 
 9             for (int i = 0; i < length; i++) {
10                 /** 遍历分别执行属性的序列化方法 */
11                 fieldSerializers[i].serialize(out, obj);
12             }
13         } catch (RuntimeException e) {
14             throw new RuntimeException(e.getMessage() + "
 class: "
15                     + obj.getClass().getName()
16                     + " (object=" + obj + ")",
17                     e);
18         } catch (IOException e) {
19             throw new IOExceptionWrapper(e.getMessage() + "
 class: "
20                     + obj.getClass().getName()
21                     + " (object=" + obj + ")",
22                     e);
23         }
24     }

写入实例的整体逻辑比较简单,就是针对每个字段都有一个序列化器,然后遍历执行所有属性对应的序列化器的序列化方法即可,如果属性是自定义类型就继续按自定义类型继续遍历属性类的所有属性。直到最终都是基本数据类型属性为止。

2.2、反序列化源码解析

和序列化相反,反序列化是通过输入流Hessian2Input对象的readObject方法来实现的,源码如下:

  1  /** 反序列化对象*/
  2     public Object readObject() throws IOException
  3     {
  4         /** 调用read()方法读取字节,第一次就读取第一个字节 */
  5         int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
  6 
  7         /** 判断字节对应的标记类型,执行对应的解析方法 */
  8         switch (tag) {
  9             case 'N':
 10                 return null;
 11 
 12             case 'T':
 13                 return Boolean.valueOf(true);
 14 
 15             case 'F':
 16                 return Boolean.valueOf(false);
 17 
 18             // direct integer
 19             case 0x80: case 0x81: case 0x82: case 0x83:
 20             case 0x84: case 0x85: case 0x86: case 0x87:
 21             case 0x88: case 0x89: case 0x8a: case 0x8b:
 22             case 0x8c: case 0x8d: case 0x8e: case 0x8f:
 23 
 24             case 0x90: case 0x91: case 0x92: case 0x93:
 25             case 0x94: case 0x95: case 0x96: case 0x97:
 26             case 0x98: case 0x99: case 0x9a: case 0x9b:
 27             case 0x9c: case 0x9d: case 0x9e: case 0x9f:
 28 
 29             case 0xa0: case 0xa1: case 0xa2: case 0xa3:
 30             case 0xa4: case 0xa5: case 0xa6: case 0xa7:
 31             case 0xa8: case 0xa9: case 0xaa: case 0xab:
 32             case 0xac: case 0xad: case 0xae: case 0xaf:
 33 
 34             case 0xb0: case 0xb1: case 0xb2: case 0xb3:
 35             case 0xb4: case 0xb5: case 0xb6: case 0xb7:
 36             case 0xb8: case 0xb9: case 0xba: case 0xbb:
 37             case 0xbc: case 0xbd: case 0xbe: case 0xbf:
 38                 return Integer.valueOf(tag - BC_INT_ZERO);
 39 
 40             /* byte int */
 41             case 0xc0: case 0xc1: case 0xc2: case 0xc3:
 42             case 0xc4: case 0xc5: case 0xc6: case 0xc7:
 43             case 0xc8: case 0xc9: case 0xca: case 0xcb:
 44             case 0xcc: case 0xcd: case 0xce: case 0xcf:
 45                 return Integer.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read());
 46 
 47             /* short int */
 48             case 0xd0: case 0xd1: case 0xd2: case 0xd3:
 49             case 0xd4: case 0xd5: case 0xd6: case 0xd7:
 50                 return Integer.valueOf(((tag - BC_INT_SHORT_ZERO) << 16)
 51                         + 256 * read() + read());
 52 
 53             case 'I':
 54                 return Integer.valueOf(parseInt());
 55 
 56             // direct long
 57             case 0xd8: case 0xd9: case 0xda: case 0xdb:
 58             case 0xdc: case 0xdd: case 0xde: case 0xdf:
 59 
 60             case 0xe0: case 0xe1: case 0xe2: case 0xe3:
 61             case 0xe4: case 0xe5: case 0xe6: case 0xe7:
 62             case 0xe8: case 0xe9: case 0xea: case 0xeb:
 63             case 0xec: case 0xed: case 0xee: case 0xef:
 64                 return Long.valueOf(tag - BC_LONG_ZERO);
 65 
 66             /* byte long */
 67             case 0xf0: case 0xf1: case 0xf2: case 0xf3:
 68             case 0xf4: case 0xf5: case 0xf6: case 0xf7:
 69             case 0xf8: case 0xf9: case 0xfa: case 0xfb:
 70             case 0xfc: case 0xfd: case 0xfe: case 0xff:
 71                 return Long.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read());
 72 
 73             /* short long */
 74             case 0x38: case 0x39: case 0x3a: case 0x3b:
 75             case 0x3c: case 0x3d: case 0x3e: case 0x3f:
 76                 return Long.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read());
 77 
 78             case BC_LONG_INT:
 79                 return Long.valueOf(parseInt());
 80 
 81             case 'L':
 82                 return Long.valueOf(parseLong());
 83 
 84             case BC_DOUBLE_ZERO:
 85                 return Double.valueOf(0);
 86 
 87             case BC_DOUBLE_ONE:
 88                 return Double.valueOf(1);
 89 
 90             case BC_DOUBLE_BYTE:
 91                 return Double.valueOf((byte) read());
 92 
 93             case BC_DOUBLE_SHORT:
 94                 return Double.valueOf((short) (256 * read() + read()));
 95 
 96             case BC_DOUBLE_MILL:
 97             {
 98                 int mills = parseInt();
 99 
100                 return Double.valueOf(0.001 * mills);
101             }
102 
103             case 'D':
104                 return Double.valueOf(parseDouble());
105 
106             case BC_DATE:
107                 return new Date(parseLong());
108 
109             case BC_DATE_MINUTE:
110                 return new Date(parseInt() * 60000L);
111 
112             case BC_STRING_CHUNK:
113             case 'S':
114             {
115                 _isLastChunk = tag == 'S';
116                 _chunkLength = (read() << 8) + read();
117 
118                 _sbuf.setLength(0);
119 
120                 parseString(_sbuf);
121 
122                 return _sbuf.toString();
123             }
124 
125             case 0x00: case 0x01: case 0x02: case 0x03:
126             case 0x04: case 0x05: case 0x06: case 0x07:
127             case 0x08: case 0x09: case 0x0a: case 0x0b:
128             case 0x0c: case 0x0d: case 0x0e: case 0x0f:
129 
130             case 0x10: case 0x11: case 0x12: case 0x13:
131             case 0x14: case 0x15: case 0x16: case 0x17:
132             case 0x18: case 0x19: case 0x1a: case 0x1b:
133             case 0x1c: case 0x1d: case 0x1e: case 0x1f:
134             {
135                 _isLastChunk = true;
136                 _chunkLength = tag - 0x00;
137 
138                 int data;
139                 _sbuf.setLength(0);
140 
141                 parseString(_sbuf);
142 
143                 return _sbuf.toString();
144             }
145 
146             case 0x30: case 0x31: case 0x32: case 0x33:
147             {
148                 _isLastChunk = true;
149                 _chunkLength = (tag - 0x30) * 256 + read();
150 
151                 _sbuf.setLength(0);
152 
153                 parseString(_sbuf);
154 
155                 return _sbuf.toString();
156             }
157 
158             case BC_BINARY_CHUNK:
159             case 'B':
160             {
161                 _isLastChunk = tag == 'B';
162                 _chunkLength = (read() << 8) + read();
163 
164                 int data;
165                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
166 
167                 while ((data = parseByte()) >= 0)
168                     bos.write(data);
169 
170                 return bos.toByteArray();
171             }
172 
173             case 0x20: case 0x21: case 0x22: case 0x23:
174             case 0x24: case 0x25: case 0x26: case 0x27:
175             case 0x28: case 0x29: case 0x2a: case 0x2b:
176             case 0x2c: case 0x2d: case 0x2e: case 0x2f:
177             {
178                 _isLastChunk = true;
179                 int len = tag - 0x20;
180                 _chunkLength = 0;
181 
182                 byte []data = new byte[len];
183 
184                 for (int i = 0; i < len; i++)
185                     data[i] = (byte) read();
186 
187                 return data;
188             }
189 
190             case 0x34: case 0x35: case 0x36: case 0x37:
191             {
192                 _isLastChunk = true;
193                 int len = (tag - 0x34) * 256 + read();
194                 _chunkLength = 0;
195 
196                 byte []buffer = new byte[len];
197 
198                 for (int i = 0; i < len; i++) {
199                     buffer[i] = (byte) read();
200                 }
201 
202                 return buffer;
203             }
204 
205             case BC_LIST_VARIABLE:
206             {
207                 // variable length list
208                 String type = readType();
209 
210                 return findSerializerFactory().readList(this, -1, type);
211             }
212 
213             case BC_LIST_VARIABLE_UNTYPED:
214             {
215                 return findSerializerFactory().readList(this, -1, null);
216             }
217 
218             case BC_LIST_FIXED:
219             {
220                 // fixed length lists
221                 String type = readType();
222                 int length = readInt();
223 
224                 Deserializer reader;
225                 reader = findSerializerFactory().getListDeserializer(type, null);
226 
227                 return reader.readLengthList(this, length);
228             }
229 
230             case BC_LIST_FIXED_UNTYPED:
231             {
232                 // fixed length lists
233                 int length = readInt();
234 
235                 Deserializer reader;
236                 reader = findSerializerFactory().getListDeserializer(null, null);
237 
238                 return reader.readLengthList(this, length);
239             }
240 
241             // compact fixed list
242             case 0x70: case 0x71: case 0x72: case 0x73:
243             case 0x74: case 0x75: case 0x76: case 0x77:
244             {
245                 // fixed length lists
246                 String type = readType();
247                 int length = tag - 0x70;
248 
249                 Deserializer reader;
250                 reader = findSerializerFactory().getListDeserializer(type, null);
251 
252                 return reader.readLengthList(this, length);
253             }
254 
255             // compact fixed untyped list
256             case 0x78: case 0x79: case 0x7a: case 0x7b:
257             case 0x7c: case 0x7d: case 0x7e: case 0x7f:
258             {
259                 // fixed length lists
260                 int length = tag - 0x78;
261 
262                 Deserializer reader;
263                 reader = findSerializerFactory().getListDeserializer(null, null);
264 
265                 return reader.readLengthList(this, length);
266             }
267 
268             case 'H':
269             {
270                 return findSerializerFactory().readMap(this, null);
271             }
272 
273             case 'M':
274             {
275                 String type = readType();
276 
277                 return findSerializerFactory().readMap(this, type);
278             }
279 
280             case 'C':
281             {
282                 readObjectDefinition(null);
283 
284                 return readObject();
285             }
286 
287             case 0x60: case 0x61: case 0x62: case 0x63:
288             case 0x64: case 0x65: case 0x66: case 0x67:
289             case 0x68: case 0x69: case 0x6a: case 0x6b:
290             case 0x6c: case 0x6d: case 0x6e: case 0x6f:
291             {
292                 int ref = tag - 0x60;
293 
294                 if (_classDefs.size() <= ref)
295                     throw error("No classes defined at reference '"
296                             + Integer.toHexString(tag) + "'");
297 
298                 ObjectDefinition def = _classDefs.get(ref);
299                 //读取实例对象
300                 return readObjectInstance(null, def);
301             }
302 
303             case 'O':
304             {
305                 int ref = readInt();
306 
307                 if (_classDefs.size() <= ref)
308                     throw error("Illegal object reference #" + ref);
309 
310                 ObjectDefinition def = _classDefs.get(ref);
311 
312                 return readObjectInstance(null, def);
313             }
314 
315             case BC_REF:
316             {
317                 int ref = readInt();
318 
319                 return _refs.get(ref);
320             }
321 
322             default:
323                 if (tag < 0)
324                     throw new EOFException("readObject: unexpected end of file");
325                 else
326                     throw error("readObject: unknown code " + codeName(tag));
327         }
328     }

这里逻辑主要是先读取标记,然后根据标记对应的类型进行判断,再执行对应的读取反解析工作。比如对象类型就会先解析到类型为'C',则会继续执行readObjectDefintion方法进行反解析类的定义,然后再执行readObject方法继续递归执行。

readObejctDefintion方法源码如下:

 1 /** 读取类的定义 */
 2     private void readObjectDefinition(Class<?> cl)throws IOException
 3     {
 4         /** 获取类型*/
 5         String type = readString();
 6         int len = readInt();
 7 
 8         SerializerFactory factory = findSerializerFactory();
 9 
10         //获取反序列化器
11         Deserializer reader = factory.getObjectDeserializer(type, null);
12         //创建属性数组
13         Object []fields = reader.createFields(len);
14         //创建属性名称数组
15         String []fieldNames = new String[len];
16 
17         //依次读取属性和属性名称的值
18         for (int i = 0; i < len; i++) {
19             String name = readString();
20             fields[i] = reader.createField(name);
21             fieldNames[i] = name;
22         }
23         //构造Object定义对象
24         ObjectDefinition def = new ObjectDefinition(type, reader, fields, fieldNames);
25         _classDefs.add(def);
26     }

读取完类的定义之后,会继续读取对象的数据,会执行到readObjectInstance方法,源码如下:

 1  /** 读取实例 */
 2     private Object readObjectInstance(Class<?> cl, ObjectDefinition def) throws IOException
 3     {
 4         String type = def.getType();
 5         /** 获取反序列化器*/
 6         Deserializer reader = def.getReader();
 7         Object []fields = def.getFields();
 8 
 9         SerializerFactory factory = findSerializerFactory();
10 
11         if (cl != reader.getType() && cl != null) {
12             reader = factory.getObjectDeserializer(type, cl);
13             /** 执行反序列化器的读取方法*/
14             return reader.readObject(this, def.getFieldNames());
15         }
16         else {
17             return reader.readObject(this, fields);
18         }
19     }

该方法的逻辑主要是先获取一个反序列化器,然后执行反序列化器的readObejct方法,执行的是UnsafeDeserializer的readObject方法,源码如下:

 /** 读取对象 */
    public Object readObject(AbstractHessianInput in, String []fieldNames)throws IOException
    {
        try {
            /** 实例化对象,通过UnSafe构造对象 */
            Object obj = instantiate();
            /** 给对象的所有属性进行赋值 */
            return readObject(in, obj, fieldNames);
        } catch (IOException e) {
            throw e;
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
        }
    }

第一步实际就是调用了Unsafe的allocationInstance构建了一个对象

protected Object instantiate()
    throws Exception
  {
    return _unsafe.allocateInstance(_type);
  }

第二步就是给该对象的所有属性进行赋值,源码如下:

 1 public Object readObject(AbstractHessianInput in, Object obj,String []fieldNames)throws IOException
 2     {
 3         try {
 4             int ref = in.addRef(obj);
 5             /** 遍历所有属性进行赋值 */
 6             for (String fieldName : fieldNames) {
 7                 FieldDeserializer reader = _fieldMap.get(fieldName);
 8                 if (reader != null)
 9                     /** 不同的类型调用不同类型的反序列化实例进行赋值 */
10                     reader.deserialize(in, obj);
11                 else
12                     in.readObject();
13             }
14             Object resolve = resolve(in, obj);
15 
16             if (obj != resolve)
17                 in.setRef(ref, resolve);
18 
19             return resolve;
20         } catch (IOException e) {
21             throw e;
22         } catch (Exception e) {
23             throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
24         }
25     }

其中FieldDeserializer有很多的子类,不同的类型有不同的反序列化方式,比如字符串属性,赋值的逻辑如下:

 1 void deserialize(AbstractHessianInput in, Object obj)
 2       throws IOException
 3     {
 4       String value = null;
 5       
 6       try {
 7         value = in.readString();
 8  
 9         _unsafe.putObject(obj, _offset, value);
10       } catch (Exception e) {
11         logDeserializeError(_field, obj, value, e);
12       }
13     }

先是读取一个字符串的值,然后还是调用UnSafe的putObejct方法进行赋值给此对象。

如果属性也是对象类型,那么就递归执行直到所有的属性都为基本数据类型并解析成功为止。

原文地址:https://www.cnblogs.com/jackion5/p/14087755.html