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 所以就发生了值覆盖问题!