读书人

Hessian源码学习(5)

发布时间: 2012-06-29 15:48:46 作者: rapoo

Hessian源码学习(五)
紧接着上一篇,我们来看看另一个序列化类JavaSerializer。
这个类一般是用来序列化我们自定义类的,所以更多的时候我们用到的是它,今天打算分析两个方面,第一是JavaSerializer本身实现,第二分析下反序列化的时候为什么会存在父类同名field值覆盖子类field问题

1.JavaSerializer实现

// 首先看一下JavaSerializer的构造方法public JavaSerializer(Class cl, ClassLoader loader){...// 存放简单类型字段     ArrayList primitiveFields = new ArrayList();// 存放复杂类型字段    ArrayList compoundFields = new ArrayList();    // 获取子类到父类所有field字段    for (; cl != null; cl = cl.getSuperclass()) {      Field []fields = cl.getDeclaredFields();      for (int i = 0; i < fields.length; i++) {Field field = fields[i];// 过滤掉这两种类型的fieldif (Modifier.isTransient(field.getModifiers())|| Modifier.isStatic(field.getModifiers()))  continue;field.setAccessible(true);// 按类型存入arrayListif (field.getType().isPrimitive()|| (field.getType().getName().startsWith("java.lang.")&& ! field.getType().equals(Object.class)))  primitiveFields.add(field);else  compoundFields.add(field);  }}// 合并成一个list并转换成数组 (ps: 这样看来之前用两个list来存放似乎没有什么意义?!)    ArrayList fields = new ArrayList();    fields.addAll(primitiveFields);    fields.addAll(compoundFields);    _fields = new Field[fields.size()];    fields.toArray(_fields);    _fieldSerializers = new FieldSerializer[_fields.length];// 获取每一个field对应的FieldSerializer(注1)    for (int i = 0; i < _fields.length; i++) {      _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());    }}

接着我们看下JavaSerializer的writeObject方法:
public void writeObject(Object obj, AbstractHessianOutput out)    throws IOException{    ...        Class cl = obj.getClass();    ...// 写类头,输出格式: 'Mt'[类名长度][类名]    int ref = out.writeObjectBegin(cl.getName());// 对于HessianOutput 总是返回-2      if (ref < -1) {      writeObject10(obj, out);    }    else {      if (ref == -1) {writeDefinition20(out);out.writeObjectBegin(cl.getName());      }      writeInstance(obj, out);    }}private void writeObject10(Object obj, AbstractHessianOutput out)    throws IOException{// 循环序列化该类的field(先子类后父类)    for (int i = 0; i < _fields.length; i++) {      Field field = _fields[i];  // 序列化field名      out.writeString(field.getName());  // 序列化field值      _fieldSerializers[i].serialize(out, obj, field);    }    // 结束标记 'z'    out.writeMapEnd();}

以上是JavaSerializer的基本实现,在(注1)有这么一段代码:
for (int i = 0; i < _fields.length; i++) { _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());}

我们看下可以获取哪些FieldSerializer,以及它们究竟是如何工作的?
private static FieldSerializer getFieldSerializer(Class type){// 对于简单类型的处理    if (int.class.equals(type)        || byte.class.equals(type)        || short.class.equals(type)        || int.class.equals(type)) {      return IntFieldSerializer.SER;    }    else if (long.class.equals(type)) {      return LongFieldSerializer.SER;    }    else if (double.class.equals(type) ||        float.class.equals(type)) {      return DoubleFieldSerializer.SER;    }    else if (boolean.class.equals(type)) {      return BooleanFieldSerializer.SER;    }    else if (String.class.equals(type)) {      return StringFieldSerializer.SER;    }    else if (java.util.Date.class.equals(type)             || java.sql.Date.class.equals(type)             || java.sql.Timestamp.class.equals(type)             || java.sql.Time.class.equals(type)) {      return DateFieldSerializer.SER;    }// 对于复杂类型的处理    else  // 所有其他类型field(比如自定义类) 就使用默认FieldSerializer      return FieldSerializer.SER;}

现在我们具体看下这些FieldSerializer(比较容易,不多解释)
static class BooleanFieldSerializer extends FieldSerializer {    static final FieldSerializer SER = new BooleanFieldSerializer();        void serialize(AbstractHessianOutput out, Object obj, Field field)      throws IOException    {      boolean value = false;      try {value = field.getBoolean(obj);      } catch (IllegalAccessException e) {log.log(Level.FINE, e.toString(), e);      }      out.writeBoolean(value);    }}static class IntFieldSerializer extends FieldSerializer {    static final FieldSerializer SER = new IntFieldSerializer();        void serialize(AbstractHessianOutput out, Object obj, Field field)      throws IOException    {      int value = 0;      try {value = field.getInt(obj);      } catch (IllegalAccessException e) {log.log(Level.FINE, e.toString(), e);      }      out.writeInt(value);    }}static class FieldSerializer {    static final FieldSerializer SER = new FieldSerializer();        void serialize(AbstractHessianOutput out, Object obj, Field field)      throws IOException    {      Object value = null;      try {value = field.get(obj);      } catch (IllegalAccessException e) {log.log(Level.FINE, e.toString(), e);      }      try {out.writeObject(value);  // 这里是怎么做的?  是不是又回到了前面? ^_^(不清楚可以看Hessian源码学习(三))      } catch (RuntimeException e) {throw new RuntimeException(e.getMessage() + "\n Java field: " + field, e);      } catch (IOException e) {throw new IOExceptionWrapper(e.getMessage() + "\n Java field: " + field, e);      }    }}


剩余的XxxFieldSerializer我就不在赘述,基本和前面一致,之前我自己看源码看到这里,我就有一个疑问,其实对于所有的Field都可以返回FieldSerializer而不必那么细致区分返回IntFieldSerializer, StringFieldSerializer等等,但是作者这里为什么还要这么做呢?

我自己的回答是加快序列化速度,不然对于每一个field 都需要走上一节说的流程,这只是我的一己之见,希望各位也能谈谈自己看法。

2.之前在文章开始,我提到在序列化的时候存在父类覆盖子类同名field的情况,现在我们就来看下源码,分析下为什么会出现这样的情况?(只是谈谈自己看法,若是有不对的地方,还希望各位能够提点一下,^_^)

JavaSerializer的实现我们前面已经分析,现在我们分析下JavaDeSerializer的实现(关键就在于序列化和反序列化的不一致引起的)
public JavaDeserializer(Class cl){    ...// 最关键的一段代码    _fieldMap = getFieldMap(cl);...}我们看下getFieldMap(cl)的实现:protected HashMap getFieldMap(Class cl)  {// 创建一个hashmap存放field (有没有觉得和JavaSerializer不一致,JavaSerializer是把field存放到一个list中去)    HashMap fieldMap = new HashMap();    // 循环读取从子类到父类的field    for (; cl != null; cl = cl.getSuperclass()) {      Field []fields = cl.getDeclaredFields();      for (int i = 0; i < fields.length; i++) {        Field field = fields[i];        if (Modifier.isTransient(field.getModifiers()) ||            Modifier.isStatic(field.getModifiers()))          continue;// 重点!!!! 由于是从子类循环到父类,所以若是存在同名字段,fieldMap中放的都是子类字段!!!!        else if (fieldMap.get(field.getName()) != null)          continue;               try {          field.setAccessible(true);        } catch (Throwable e) {          e.printStackTrace();        }Class type = field.getType();FieldDeserializer deser;if (String.class.equals(type))  deser = new StringFieldDeserializer(field);else if (byte.class.equals(type)) {  deser = new ByteFieldDeserializer(field);}else if (short.class.equals(type)) { // 省略}else {  deser = new ObjectFieldDeserializer(field);}        fieldMap.put(field.getName(), deser);      }    }    return fieldMap;  }


从上面代码我们得出一个结论:对于同名字段fieldMap中存放的是子类field; 另外在序列化的时候,对于同名field是子类值在前,父类值在后,于是赋值就变成:子类值->子类field, 父类值->子类field 所以就发生了值覆盖问题!

读书人网 >开源软件

热点推荐