Hessian源码学习(五)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Hessian源码学习(五)

Hessian源码学习(五)

 2011/12/29 17:28:08  DiaoCow  http://diaocow.iteye.com  我要评论(0)
  • 摘要:紧接着上一篇,我们来看看另一个序列化类JavaSerializer。这个类一般是用来序列化我们自定义类的,所以更多的时候我们用到的是它,今天打算分析两个方面,第一是JavaSerializer本身实现,第二分析下反序列化的时候为什么会存在父类同名field值覆盖子类field问题1.JavaSerializer实现//首先看一下JavaSerializer的构造方法publicJavaSerializer(Classcl,ClassLoaderloader){..
  • 标签:学习 源码
紧接着上一篇,我们来看看另一个序列化类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];
		
		// 过滤掉这两种类型的field
		if (Modifier.isTransient(field.getModifiers())
			|| Modifier.isStatic(field.getModifiers()))
		  continue;

		field.setAccessible(true);
	
		// 按类型存入arrayList
		if (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);  // 这里是怎么做的?  是不是又回到了上一节? ^_^
      } 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 所以就发生了值覆盖问题!
发表评论
用户名: 匿名