Hessian序列化对象之CollectionSerializer(六)

来源:互联网 发布:航天信息a6软件下载 编辑:程序博客网 时间:2024/05/20 14:17

在Hessian中所有的集合类型都是通过CollectionSerializer对象来进行的序列化,为什么是所有的集合类型呢,让我们看一下具体的代码段,该代码段是SerializerFactory类的loadSerializer方法中的一段代码,该方法的具体功能在前面的博客中有详细说明,loadSerializer()方法负责根据调用远程方法的参数的类型选取对应的序列化对象

我们知道Collection是所有集合类型的超接口,所以在Hessian中所有的集合类型对应的序列化对象都是CollectionSerializer

    else if (Collection.class.isAssignableFrom(cl)) {//如果Collection和cl表示的类相同,或是cl的超类或超接口,则返回true      if (_collectionSerializer == null) {        _collectionSerializer = new CollectionSerializer();      }      return _collectionSerializer;    }

知道了什么样的Class对象使用CollectionSerializer序列化对象,下面来看看CollectionSerializer的writeObject()方法是如何实现的

public void writeObject(Object obj, AbstractHessianOutput out)    throws IOException  {    if (out.addRef(obj))      return;    Collection list = (Collection) obj;    Class cl = obj.getClass();    boolean hasEnd;        if (cl.equals(ArrayList.class)        || ! Serializable.class.isAssignableFrom(cl)) {      hasEnd = out.writeListBegin(list.size(), null);//代码1    }    else if (! _sendJavaType) {      hasEnd = false;            // hessian/3a19      for (; cl != null; cl = cl.getSuperclass()) {        if (cl.getName().startsWith("java.")) {          hasEnd = out.writeListBegin(list.size(), cl.getName());          break;        }      }            if (cl == null)        hasEnd = out.writeListBegin(list.size(), null);    }    else {      hasEnd = out.writeListBegin(list.size(), obj.getClass().getName());//代码2    }    Iterator iter = list.iterator();    while (iter.hasNext()) {//代码3      Object value = iter.next();      out.writeObject(value);    }    if (hasEnd)      out.writeListEnd();  }
我们还是先来看下主流程,如果是ArrayList或者其他实现了Serializer接口的集合会走到代码1处,writeListBegin方法负责将该集合的size写入到流中,如果是Collection的其他子类会走到代码2处,去吧就是其他类型的集合要将集合的name写到流中而ArrayList是做为集合的默认实现,将长度写到集合中后就开始写具体的内容了,代码3的while循环会遍历循环的内容然后调用HessianOutput的writeObject()方法将对象写入到流中,问题来了List中的是自定义的对象HessianOutput是如何将自定义的对象写入到流中的呢?

writeObject方法又会去根据object的类型获取对应的序列化对象,这其实是一个递归的过程,递归的结束条件就是直到写出的对象是基本类型的对象还有几个特殊的对象为止

(下篇博客会介绍自定义对象是如何序列化的)

  public void writeObject(Object object)    throws IOException  {    if (object == null) {      writeNull();      return;    }    Serializer serializer;    serializer = _serializerFactory.getSerializer(object.getClass());    serializer.writeObject(object, this);  }
看完了主流程,我们来看一下在CollectionSerializer的writeObject()中最上面的一行代码是out.addref(obj),如果该方法为空则直接返回,不向流中写入内容,这是怎么回事呢?

addref方法的代码如下,该方法的意思是如果有一个List对象,向流中写入了两次而且两次写入的List对象有list1==list2(注意是“==”不是equals)那么第二次就不像流中写入该对象了,直接写入该对象的ref就可以了,在反序列化的时候可以根据ref解析出该对象

public boolean addRef(Object object)    throws IOException  {    if (_refs == null)      _refs = new IdentityHashMap();    Integer ref = (Integer) _refs.get(object);    if (ref != null) {      int value = ref.intValue();            writeRef(value);      return true;    }    else {      _refs.put(object, new Integer(_refs.size()));            return false;    }  }

接下来让我们看看CollectionDeserializer,首先调用createList()方法确定要创建的集合对象,具体创建哪个集合对象是从输入流中解析出来的,然后将对象加入到ref集合里,然后代码3处循环解析具体的对象,解析具体对象的过程还是一个递归的过程,最后代码4从输入流中读取结束符,然后返回解析完成的对象

  public Object readList(AbstractHessianInput in, int length)    throws IOException  {    Collection list = createList();//代码1    in.addRef(list);//代码2    while (! in.isEnd())//代码3      list.add(in.readObject());    in.readEnd();//代码4    return list;  }