在Hessian中所有的序列化对象和反序列化对象都是成对存在的,在接下来分析Hessian序列化对象的博客中,会成对分析,例如本篇分析BasicSerializer的同时也会分析BasicDeserializer
在Hessian中8个基本类型的序列化
boolean,byte,short,int,long,float,double,char
8个基本类型对应的包装类的序列化
Boolean,Byte,Short,Integer,Long,Float,Double,Character
8种基本类型对应的数组
boolean[],byte[],short[],int[],long[],float[],double[],char[]
还有
void,String,Date,String[],Number
上述类型的序列化功能都是由BasicSerializer实现的
Hessian是在ContextSerializerFactory中来初始化上述类对象和序列化对象的对应关系的我们来看一下Hessian是如何做的
ContextSerializerFactory的静态初始化块如下(代码太长,只展示了int类型对应的序列化对象,其余因为篇幅原因省略了)
static {
_staticSerializerMap = new HashMap();
_staticDeserializerMap = new HashMap();
_staticClassNameMap = new HashMap();
addBasic(void.class, "void", BasicSerializer.NULL);
addBasic(Integer.class, "int", BasicSerializer.INTEGER);
addBasic(int.class, "int", BasicSerializer.INTEGER);
addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY);
// hessian/3bb5
_staticDeserializerMap.put(StackTraceElement.class.getName(),
new StackTraceElementDeserializer());
ClassLoader systemClassLoader = null;
try {
systemClassLoader = ClassLoader.getSystemClassLoader();
} catch (Exception e) {
}
_systemClassLoader = systemClassLoader;
}
在静态初始化块中调用静态方法addBasic()来初始化对应关系,addBasic代码如下,类的基本名称和序列化对象的关系被放到了_staticSerializerMap中(注意调用int的getName方法的返回值为int,而调用Integer方法的返回值为java.lang.Integer,这两者是不一样的),而_staticDeserializerMap和_staticClassNameMap是反序列化相关的,
后面博客讲到反序列化时再详细说明
private static void addBasic(Class cl, String typeName, int type)
{
_staticSerializerMap.put(cl.getName(), new BasicSerializer(type));
Deserializer deserializer = new BasicDeserializer(type);
_staticDeserializerMap.put(cl.getName(), deserializer);
_staticClassNameMap.put(typeName, deserializer);
}
这里虽然存放了类和序列化对象的对应关系,但是根据类名获取序列化对象的方法是从_serializerClassMap中拿的,而不是_staticSerializerMap,代码如下
public Serializer getSerializer(String className)
{
Serializer serializer = _serializerClassMap.get(className);
if (serializer == AbstractSerializer.NULL)
return null;
else
return serializer;
}
这是因为在创建ContextSerializerFactory对象时调用了它的init(),在init()方法中将_staticSerializerMap中的内容复制到了_serializerClassMap中
====================
到此为止通过类名已经拿到了对应的序列化对象,这时会调用writeObject()方法真正的将对象写出到流中,让我们看看BasicObject的writeObject()方法是如何实现的(截取部分代码)
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException
{
switch (_code) {
case BYTE:
case SHORT:
case INTEGER:
out.writeInt(((Number) obj).intValue());
break;
case STRING:
out.writeString((String) obj);
break;
case STRING_BUILDER:
out.writeString(((StringBuilder) obj).toString());
break;
case DATE:
out.writeUTCDate(((Date) obj).getTime());
break;
case INTEGER_ARRAY:
{
if (out.addRef(obj))
return;
int []data = (int []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[int");
for (int i = 0; i < data.length; i++)
out.writeInt(data[i]);
if (hasEnd)
out.writeListEnd();
break;
}
case CHARACTER_ARRAY:
{
char []data = (char []) obj;
out.writeString(data, 0, data.length);
break;
}
case OBJECT_ARRAY:
{
if (out.addRef(obj))
return;
Object []data = (Object []) obj;
boolean hasEnd = out.writeListBegin(data.length, "[object");
for (int i = 0; i < data.length; i++) {
out.writeObject(data[i]);
}
if (hasEnd)
out.writeListEnd();
break;
}
case NULL:
out.writeNull();
break;
case OBJECT:
ObjectHandleSerializer.SER.writeObject(obj, out);
break;
case BYTE_HANDLE:
out.writeObject(new ByteHandle((Byte) obj));
break;
case SHORT_HANDLE:
out.writeObject(new ShortHandle((Short) obj));
break;
case FLOAT_HANDLE:
out.writeObject(new FloatHandle((Float) obj));
break;
default:
throw new RuntimeException(_code + " unknown code for " + obj.getClass());
}
}
实际上BasicSerializer是调用了HessianOutput的write***()方法将信息写出到流中的,具体代码如下
向流中写一个int类型的变量
public void writeInt(int value)
throws IOException
{
os.write('I');
os.write(value >> 24);
os.write(value >> 16);
os.write(value >> 8);
os.write(value);
}
其余的write***()方法就不一一展示了,有兴趣的同学可以去GitHub上下载Hessian的源码看一下HessianOutput类具体是如何实现的
当把服务端收到客户端序列化过来的对象后会进行反序列化,下面来看一下BasicDeserializer的readObject()方法是如何实现的,可以看到反序列化调用的是AbstractHessianInput的实现类HessianInput的方法来实现的
public Object readObject(AbstractHessianInput in)
throws IOException
{
switch (_code) {
case NULL:
// hessian/3490
in.readObject();
return null;
case BOOLEAN:
return Boolean.valueOf(in.readBoolean());
case BYTE:
return Byte.valueOf((byte) in.readInt());
case SHORT:
return Short.valueOf((short) in.readInt());
case INTEGER:
return Integer.valueOf(in.readInt());
case LONG:
return Long.valueOf(in.readLong());
case FLOAT:
return Float.valueOf((float) in.readDouble());
case DOUBLE:
return Double.valueOf(in.readDouble());
case STRING:
return in.readString();
case OBJECT:
return in.readObject();
case CHARACTER:
{
String s = in.readString();
if (s == null || s.equals(""))
return Character.valueOf((char) 0);
else
return Character.valueOf(s.charAt(0));
}
case CHARACTER_OBJECT:
{
String s = in.readString();
if (s == null || s.equals(""))
return null;
else
return Character.valueOf(s.charAt(0));
}
case DATE:
return new Date(in.readUTCDate());
case NUMBER:
return in.readObject();
case BYTE_ARRAY:
return in.readBytes();
case CHARACTER_ARRAY:
{
String s = in.readString();
if (s == null)
return null;
else {
int len = s.length();
char []chars = new char[len];
s.getChars(0, len, chars, 0);
return chars;
}
}
case BOOLEAN_ARRAY:
case SHORT_ARRAY:
case INTEGER_ARRAY:
case LONG_ARRAY:
case FLOAT_ARRAY:
case DOUBLE_ARRAY:
case STRING_ARRAY:
{
int code = in.readListStart();
switch (code) {
case 'N':
return null;
case 0x10: case 0x11: case 0x12: case 0x13:
case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1a: case 0x1b:
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
int length = code - 0x10;
in.readInt();
return readLengthList(in, length);
default:
String type = in.readType();
length = in.readLength();
return readList(in, length);
}
}
default:
throw new UnsupportedOperationException();
}
}
下面这段代码就是HessianInput类的readInt方法,可以看到先从流中读取了一个字节,通过该字节来判断接下来的变量是boolean类型的还是int类型还是其他类型
public int readInt()
throws IOException
{
int tag = read();
switch (tag) {
case 'T': return 1;
case 'F': return 0;
case 'I': return parseInt();
case 'L': return (int) parseLong();
case 'D': return (int) parseDouble();
default:
throw expect("int", tag);
}
}
思考一个问题
为什么要把写基本类型到流中的实现比如writeInt()方法在HessianOutput中实现而不是在BasicSerializer中实现呢?