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() + "\n class: "
15                     + obj.getClass().getName()
16                     + " (object=" + obj + ")",
17                     e);
18         } catch (IOException e) {
19             throw new IOExceptionWrapper(e.getMessage() + "\n 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方法進行賦值給此對象。

如果屬性也是對象類型,那麼就遞歸執行直到所有的屬性都爲基本數據類型並解析成功爲止。

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