一、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方法進行賦值給此對象。
如果屬性也是對象類型,那麼就遞歸執行直到所有的屬性都爲基本數據類型並解析成功爲止。