java序列化2
下面我们再看下反序列化
FileInputStream fis =?new?FileInputStream("d:\\hessianPerson.txt");
Hessian2Input hi =new?Hessian2Input(fis);
Person p = (Person) hi.readObject();
和java序列化一样也是readObject方法,这里面有什么呢?
int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();? //第一个字符,就是tag,此时C,也就是类
case 'C':
????? {
readObjectDefinition(null); //读取类型信息
return readObject();??????????? //读取属性信息,并将属性信息设置到新建的对象中
????? }
读取类型信息也很简单
? private void readObjectDefinition(Class<?> cl)
??? throws IOException
? {
??? String type = readString();
??? int len = readInt();
??? SerializerFactory factory = findSerializerFactory();
??? Deserializer reader = factory.getObjectDeserializer(type, null);
??? Object []fields = reader.createFields(len);
??? String []fieldNames = new String[len];
??? for (int i = 0; i < len; i++) {
????? String name = readString();
?????
??????fields[i] = reader.createField(name);
????? fieldNames[i] = name;
??? }
???
????ObjectDefinition def = new ObjectDefinition(type, reader, fields, fieldNames);
? }
1、??首先读取?类路径
2、??读取属性个数
3、??获得此种类型的反序列化类,此时是UnsafeDeserializer类
4、??读取属性的名称
5、??根据类路径(也就是类类型)和属性的名称,创建一个ObjectDefinition
?
上面基本上就是java和hessian的序列化和发序列化的过程,到这个地方的时候我们比较一下,一个重要的问题,继承的问题
1、??继承的类没有实现序列化接口
Java序列化??在序列化文件中,不存在任何父类的信息,即使已经设置了父类属性的值,也不会被序列化到,在反序列化的过程中,父类字段值就为相应属性的默认值。
Hessian序列化,在序列化文件中,存在的字段,如果设置了父类属性(和子类不重复)的值,会被序列化到文件中,作为子类的属性在用,因此在反序列化中,可以得到这些属性。
2、??继承的类实现了序列化接口
Java序列化?在序列化中,父类的字段和子类的字段是分开的,首先是子类的字段,及其值,然后是父类的类型,字段,值等,因此在反序列化的时候,可以分清父类和子类的值
而在hessian序列化中,可以看到实现和没有实现是没有区别的,还是一样的,忽略了父类的类型,仅仅是将父类的属性和值放到了序列化文件中,在反序列化的时候就分不清父类和子类的值了。这一点有可能造成一些比较麻烦的问题,参考http://jameswxx.iteye.com/blog/1071476??这个应该是我们公司的人遇到的,但是模拟了下,应该还算编码不规范导致的。
----------------------------------------------------hessian序列化完成--------------------------------------------------------
总结下?hessian序列化和java序列化的区别
1、??hessian序列化针对某些特定的类型进行优化,使得这些类型的序列化更快和更小
2、??hessian序列化不管父类有没有序列化,将其当做子类属性来处理。
3、??hessian序列化?在某些情况(编码不规范)下,会有一些小问题。
-----------------------------------------------------fastjson序列化--------------------------------------------------------------------
根据上面的思路,我们来看下fastjson,号称史上最快,序列化结果最小的工具
Person?myPerson =?new?Person();?? myPerson.setAge(10);??? myPerson.setName("wangshiji");
Object text = JSON.toJSONString(myPerson);???? System.out.println(text);
结果为{"age":10,"name":"wangshiji"}
下面分析下代码:
SerializeWriter out = new SerializeWriter();
??????? try {
??????????? JSONSerializer serializer = new JSONSerializer(out);
??????????? for (com.alibaba.fastjson.serializer.SerializerFeature feature : features) {
??????????????? serializer.config(feature, true);
??????????? }
??????????? serializer.write(object);
??????????? return out.toString();
??????? } finally {
??????????? out.close();
?????? ?}
根据温少的文章?http://www.iteye.com/topic/1113183??,快的原因之一是自行编写类似StringBuilder的工具类SerializeWriter,仔细的看了下,没有发现提高性能的方式,不过这句话也是对的public void writeIntAndChar(int i, char c) {},这样的方法一次性把两个值写到buf中去,能够减少一次越界检查。呵呵。使用ThreadLocal来缓存buf。这个确实能提高性能,因为StringBuffer有synchronized标示符,而StringBuilder不是线程安全的,但是由于用的是软引用,有可能在GC的时候,将其回收也是一个问题。
下面我们来分析serializer.write(object);??这个代码结构
Class<?> clazz = object.getClass();??????????????????? //得到当前类的类型
ObjectSerializer writer = getObjectWriter(clazz);????? //通过类型,得到相应的序列化器
writer.write(this, object,?null,?null);??????????????? //通过相应的序列化器,将object进行序列化
?
跟进去就会发现?这里面会判断?clazz的类型,然后赋予已经定义好的序列化器,比如MapSerializer,ListSerializer。。。等,如果是自定义的pojo怎么办呢?因为不可能将所有的类型都写一遍的,这个地方就体现出fastjson高明的地方了,其实这个问题在hessian中也会遇到,hessian是不管当前类的类型,用类中属性的类型进行序列化,如果属性还是自定义pojo,则进行递归,这个方式是好的,但是fastjson更加高明,通过asm工具?直接根据当前类型,生成了一个序列化器,就是通过这个方法生成的
config.createJavaBeanSerializer(clazz)
至于asm,大家可以看下,还是比较简单的,但是这个生成的过程还是挺复杂的,可以将他那个反射类拿出来,然后在反编译就可以看到原貌了。
简单来说,就是首先得到所有属性类型,然后再调用相应的序列化器将其序列化,思想和hessian一致。如果属性还是自定义pojo,则进行递归。
?
反序列化的内容,就看下上面那篇文章吧,http://www.iteye.com/topic/1113183,有很多料的
?
?