一、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方法进行赋值给此对象。
如果属性也是对象类型,那么就递归执行直到所有的属性都为基本数据类型并解析成功为止。