今天重新看了一下Hessian的
序列化类,
发现了一个之前被自己忽略的地方,而这应该也是Hessian序列化较快的原因之一。
在大多数序列化类开始之前都有这么一段代码:
if (out.addRef(obj))
return;
//省略具体序列化code...
我们看下addRef(obj)做了些什么:
/**
* If the object has already been written, just write its ref.
*
* @return true if we're writing a ref.
*/
public boolean addRef(Object object)
throws IOException
{
// 创建IdentityHashMap(不同于hashmap)
if (_refs == null)
_refs = new IdentityHashMap();
// 检查是否已经序列化过该object
Integer ref = (Integer) _refs.get(object);
// 已经序列化过,则只需要序列化该object的一个标识(一个整型值)
if (ref != null) {
int value = ref.intValue();
writeRef(value);
return true;
}
// 第一次序列化该对象,则存入该object的标示(当前map.size())
else {
_refs.put(object, new Integer(_refs.size()));
return false;
}
}
public void writeRef(int value)
throws IOException
{
os.write('R');
os.write(value >> 24);
os.write(value >> 16);
os.write(value >> 8);
os.write(value);
}
这样子当序列化同一个对象时(即引用相同),
第二次序列化只是序列化该对象的标识(一个整型值),并且在IdentityHashMap中存放所有对象的标识!
我们具体看一个
例子:
OutputStream os = new FileOutputStream("/hessianOutput");
AbstractHessianOutput out = new HessianOutput(os);
out.setSerializerFactory(new SerializerFactory());
Boolean[] array = new Boolean[]{true,false};
// 对于同一个对象序列化2次
out.writeObject(array);
out.writeObject(array);
我们看一下序列化的结果:
红色线框代表标识符,蓝色线框代表标识值
可以看到第二次序列化时,由于之前已经序列化该对象所以这次只是序列化该对象的一个标识,对照前面代码可以知道是0;
序列化我们说到这里,但是现在又有一个问题,在反序列化的时候是如
何处理这些对象标识的呢? 那我们就来看下HessianInput.readOject(cl):
/**
* Reads an object from the input stream with an expected type.
*/
public Object readObject(Class cl)
throws IOException
{
if (cl == null || cl == Object.class)
return readObject();
int tag = read();
switch (tag) {
case 'N':
return null;
case 'M':
{
String type = readType();
Deserializer reader;
reader = _serializerFactory.getObjectDeserializer(type);
if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))
return reader.readMap(this);
reader = _serializerFactory.getDeserializer(cl);
return reader.readMap(this);
}
case 'V':
{
String type = readType();
int length = readLength();
Deserializer reader;
reader = _serializerFactory.getObjectDeserializer(type);
if (cl != reader.getType() && cl.isAssignableFrom(reader.getType()))
return reader.readList(this, length);
reader = _serializerFactory.getDeserializer(cl);
Object v = reader.readList(this, length);
return v;
}
// 如果是一个引用标识:
case 'R':
{
// 读取标示的值(比如刚才例子那段代码就是0)
int ref = parseInt();
// 返回对象
return _refs.get(ref);
}
case 'r':
{
String type = readType();
String url = readString();
return resolveRemote(type, url);
}
}
_peek = tag;
Object value = _serializerFactory.getDeserializer(cl).readObject(this);
return value;
}
也许大家会对_refs.get(ref)有点疑问,_refs其实是一个ArrayList,并且每当反序列化读取一个对象时(case 'M', case 'V'等等),就会把这个对象放入_refs中,那么当下次反序列化同一个对象时就可以直接从ArrayList中获取
这个特性我想也是Hessian序列化快的原因之一。
- 大小: 9.9 KB