当前位置: 代码迷 >> JavaScript >> alibaba fastjson(json序列化器)序列化一部分源码解析
  详细解决方案

alibaba fastjson(json序列化器)序列化一部分源码解析

热度:1551   发布时间:2012-09-11 10:49:03.0
alibaba fastjson(json序列化器)序列化部分源码解析

本文copy自http://www.flydmeng.com/index.php/code/alibaba-fastjson-json-serializer-chapter-source-analyse-one-global-analyse.html

?

?

fastjson官方地址: http://code.alibabatech.com/wiki/display/FastJSON/Home
??? 从javaeye上看到了阿里一位人士写的fastjson,特别是其中如何将java对象序列化成json字符串这段。笔者比较关注,因为在笔者的项目中就用了一个json序列化器(造的轮子)。就下载下来看了一看,先不说和笔者所用的轮子有何区别,单就用了一个简单的测试器,来测试一下两者的处理速度。测试代码就不贴了,简单地说下测试结果。在jvm充分优化的情况下(for循环执行了很多次之后),笔者所使用的java序列化器处理速度不是很均匀,在结尾有短暂的变化(可能与虚拟机回收有关系);而fastjson在后面的处理过程当中,一般很均匀(后来发现与使用的buf分配方式有关)。最主要的区别莫在于,fastjson的速度那是不能对比了。
??? 经过分析源码之后,发现fastjson在处理json优化上面还是下了很大的工夫的。笔者准备从以下几个方面对fastjson作一个简单的解析,也让使用fastjson的同学对fastjson有一个简单的认识。
??????? 1??? 总体分析??? 分析json序列化的总体思路和解析过程
??????? 2??? 性能分析A? 针对字符生产部分(即outWriter)对不同类型数据的处理和与性能相关处理部分
??????? 3??? 性别分析B? 针对序列化过程部分(即objectSerializer)对不同类型的序列化过程处理和与性能相关处理部分
??????? 4??? 对象解析分析??? 对javaBean解析部分和针对字段输出部分的处理和解析
??? 源码分析基于1.0.5版本。

??? 总体分析,首先上图,即fastjson的总体处理思想,其实也是所有json序列化器需要考虑的问题。

?

? ? 在这里,需要考虑的主要有两个部分,一是临时保存在序列化过程中用于储存数据的容器,二是处理对象序列化的序列化器。
? ? 在fastjson中,保存数据的容器使用了wirter,字符输出流,而且是自实现的一个字符输出流。相对原来的writer,追加了很多需要输出的信息的实现,比如输出一个字符串,输出一个字符,输出一个long类型数据等。而处理对象序列化的序列化器,而使用了责任链模式和工厂模式,将不同类型的java对象分散到不同的序列化器当中。而每个序列化器只处理与自身类型相对应的数据信息,这样就避免了在处理时,各种情况交织在一块,逻辑混乱的问题。
? ? 下面就源码本身作一个分析,其中结合两个部分进行分析。

?

? ? 代码分析部分

????首先,将一个对象序列化json字符串调用的是JSON对象的toJSONString方法,这里调用的是无参数方法。(注:本文不分析采用vistor实现json序列化代码的部分)。具体代码如下所示:

第一行,新产生的一个数据保存器,储存在序列化过程中产生的数据;第二行,产生统一的json序列化器,其中使用了outWriter,此类即json序列化的统一处理器;第三行,调用序列化方法开始序列化对象,以产生json字符串信息;第四行,返回已经储存的json信息。

?

Java代码??收藏代码
  1. SerializeWriter?out?=?new?SerializeWriter();??
  2. ???????JSONSerializer?serializer?=?new?JSONSerializer(out);??
  3. ???????serializer.write(object);??
  4. ???????return?out.toString();??
?

?

?

??? 数据保存器(序列化输出容器)
???
????SerializeWriter是一个用于储存在序列化过程中产生的数据信息,它与jdk中的StringBuiler有着类似的功能,即将不同的数据填充到此容器中。之所以不使用StringBuilder的原因之一在于StringBuilder没有提供一些特别为性能优化的方法,并且StringBuilder在处理过程中增加了多余的操作(如新分配对象)。该容器的主要功能就是接收不同的数据,并将这些数据存储到该内部的一个字符数组当中,同时记录字符总数。
??? 既然充当了一个数据输出的角色,那么就可以往其中输入任何的数据,包括int,byte,short等基本类型和对应的包装类型,也包括日期数据,以及经常使用的字符串数据等。对于在这些数据类型之外的其它类型,由于json的特殊结构,所有的高级类型均可以转化于这些基础类型的组织体,所以不需要再针对高级类型作处理了(这些是序列化器应该考虑的问题)。

??? 首先对SerializeWriter的方法(输出和追加)作一个预览:

方法总共可以分五个部分,第一个部分是针对writer基本功能一个扩展,即支持输出int,字符,以及字符数组,追加字符数组(包括字符串)等;第二个部分提供了写整形和长整形的基本方法;第三个部分是提供写基本数据类型数组的支持;第四个部分是提供写一个数字+一个字符的形式,比如数据+[,\],}]这种格式;第五个部分是提供写数据串,主是是针对字符串追加双引号或单引号(以支持标准json)。

?

Java代码??收藏代码
  1. public?void?write(int?c)??
  2. public?void?write(char?c)??
  3. public?void?write(char?c[],?int?off,?int?len)??
  4. public?void?write(String?str,?int?off,?int?len)??
  5. public?SerializeWriter?append(CharSequence?csq)??
  6. public?SerializeWriter?append(CharSequence?csq,?int?start,?int?end)??
  7. public?SerializeWriter?append(char?c)??
  8. ???
  9. public?void?writeInt(int?i)??
  10. public?void?writeLong(long?i)??
  11. ???
  12. public?void?writeBooleanArray(boolean[]?array)??
  13. public?void?writeShortArray(short[]?array)??
  14. public?void?writeByteArray(byte[]?array)??
  15. public?void?writeIntArray(int[]?array)??
  16. public?void?writeIntArray(Integer[]?array)??
  17. public?void?writeLongArray(long[]?array)??
  18. ???
  19. public?void?writeIntAndChar(int?i,?char?c)??
  20. public?void?writeLongAndChar(long?i,?char?c)??
  21. ???
  22. public?void?writeStringWithDoubleQuote(String?text)??
  23. public?void?writeKeyWithDoubleQuote(String?text)??
  24. public?void?writeStringWithSingleQuote(String?text)??
  25. public?void?writeStringArray(String[]?array)??
  26. public?void?writeKeyWithSingleQuote(String?text)??
  27. public?void?writeKeyWithDoubleQuoteIfHashSpecial(String?text)??
  28. public?void?writeKeyWithSingleQuoteIfHashSpecial(String?text)??
?

?

??? 五个部分的方法,每个部分都有其特殊的作用和意义,针对最常用的数字和字符串作了特别的对待。

??? 在实现上面,SerializeWriter使用了一个内部的字符数组作为数据的储存器,同时使用了一个计数器计算当前存储的字符量。既然使用了字符数组,那么肯定有相关的操作,如字符扩容等。整个写数据的过程,其实就是往这个字符数组追加数据的过程,需要考虑只是如何追加数据的问题,即上面所列出的这么多些方法。在最终写完数据之后,即可将这个字符数组转为我们所需要的字符串了。

??? 对象序列化入口

??? JsonSerializer,准备地讲,这个类不应该叫这个名字,因为它与其它的对象序列化器相混淆了。这只是一个提供对象序列化的一个入口;同时,它持有所有具体负责对象序列化工作类的引用。将这些序列化器集中起来,需要用到哪个对象序列化器时,就取出这个序列化器,并调用相应的序列化方法。
??? 既然是对象序列化入口,它就需要关注两个事情。一是我们究竟有哪些序列化器可以使用,二是对于一个对象,应该使用哪一个序列化器来进行工作。对于这两个问题,JsonSerializer内部持有一个JSONSerializerMap的属性,即表示应该序列化的对象类型和对应的序列化器的一个映射。我们来看默认的构造方法,它使用了默认的全局对象类型和对象序列化器映射:

?

Java代码??收藏代码
  1. public?JSONSerializer(SerializeWriter?out){??
  2. ????????this(out,?JSONSerializerMap.getGlobalInstance());??
  3. ????}??
?

?

这时使用了全局的一个对象序列化器映射,加上后面在getObjectWriter中追加的对象序列化器映射。在整个jsonSerializer中,可以使用的对象序列化器有以下这些:

?

?

?

?

Java代码??收藏代码
  1. put(Boolean.class,?BooleanSerializer.instance);??
  2. ????????put(Byte.class,?ByteSerializer.instance);??
  3. ????????put(Short.class,?ShortSerializer.instance);??
  4. ????????put(Integer.class,?IntegerSerializer.instance);??
  5. ????????put(Long.class,?LongSerializer.instance);??
  6. ????????put(Float.class,?FloatSerializer.instance);??
  7. ????????put(Double.class,?DoubleSerializer.instance);??
  8. ????????put(BigDecimal.class,?BigDecimalSerializer.instance);??
  9. ????????put(BigInteger.class,?BigIntegerSerializer.instance);??
  10. ????????put(String.class,?StringSerializer.instance);??
  11. ????????put(byte[].class,?ByteArraySerializer.instance);??
  12. ????????put(short[].class,?ShortArraySerializer.instance);??
  13. ????????put(int[].class,?IntArraySerializer.instance);??
  14. ????????put(long[].class,?LongArraySerializer.instance);??
  15. ????????put(float[].class,?FloatArraySerializer.instance);??
  16. ????????put(double[].class,?DoubleArraySerializer.instance);??
  17. ????????put(boolean[].class,?BooleanArraySerializer.instance);??
  18. ????????put(Integer[].class,?IntegerArraySerializer.instance);??
  19. ????????put(String[].class,?StringArraySerializer.instance);??
  20. ????????put(Object[].class,?ObjectArraySerializer.instance);??
  21. ????????put(Class.class,?ClassSerializer.instance);??
  22. ???
  23. ????????//?atomic??
  24. ????????put(AtomicBoolean.class,?AtomicBooleanSerializer.instance);??
  25. ????????put(AtomicInteger.class,?AtomicIntegerSerializer.instance);??
  26. ????????put(AtomicLong.class,?AtomicLongSerializer.instance);??
  27. ????????put(AtomicReference.class,?AtomicReferenceSerializer.instance);??
  28. ????????put(AtomicIntegerArray.class,?AtomicIntegerArraySerializer.instance);??
  29. ????????put(AtomicLongArray.class,?AtomicLongArraySerializer.instance);??
  30. ???
  31. ????????//?jmx??
  32. ????????put(CompositeData.class,?CompositeDataSerializer.instance);??
  33. ????????put(CompositeDataSupport.class,?CompositeDataSerializer.instance);??
  34. ????????put(TabularData.class,?TabularDataSerializer.instance);??
  35. ????????put(TabularDataSupport.class,?TabularDataSerializer.instance);??
  36. ????????put(ObjectName.class,?ObjectNameSerializer.instance);??
  37. ????????put(SimpleType.class,?SimpleTypeSerializer.instance);??
  38. ???
  39. ????????//在执行过程中追加部分??
  40. ????????????????mapping.put(clazz,?MapSerializer.instance);??
  41. ????????????????mapping.put(clazz,?ListSerializer.instance);??
  42. ????????????????mapping.put(clazz,?CollectionSerializer.instance);??
  43. ????????????????mapping.put(clazz,?DateSerializer.instance);??
  44. ????????????????mapping.put(clazz,?JSONAwareSerializer.instance);??
  45. ????????????????mapping.put(clazz,?JSONStreamAwareSerializer.instance);??
  46. ????????????????mapping.put(clazz,?EnumSerializer.instance);??
  47. ????????????????mapping.put(clazz,?new?ArraySerializer(compObjectSerializer));??
  48. ????????????????mapping.put(clazz,?new?ExceptionSerializer(clazz));??
  49. ????????????????mapping.put(clazz,?new?JavaBeanSerializer(clazz));??

?

? ? ?这些序列化器,覆盖了基本数据,字符串类型,日期,以及集合,map,以及javaBean的所有序列化器。因为不存在没有匹配不了的序列化器。既然有个序列化器,就可以执行序列化工作了。即到了序列化入口应该做的工作了。

?

Java代码??收藏代码
  1. Class<?>?clazz?=?object.getClass();??
  2. ????????????ObjectSerializer?writer?=?getObjectWriter(clazz);??
  3. ????????????writer.write(this,?object);??

? ? ?首先获得当前序列化对象所在的类型,再根据类型取得相对应的序列化器,最后使用序列化器进行正式的序列化工作。

?

?

??? 序列化过程

??? 正如上面所说,进入序列化工作之后,即是针对每一种类型进行序列化处理了。该序列化工作使用了统一的方法,即实现了统一的序列化方法:

?

Java代码??收藏代码
  1. void?write(JSONSerializer?serializer,?Object?object)?throws?IOException??

?

?

?

? ? 该方法在抽象类(可以说是接口)ObjectSerializer中定义,即所有的序列化器都继承了此类,并实现了此方法用于处理不同的情形。对于上层调用(如JsonSerializer),不需要考虑每一个类型的序列化工作是如何实现的,只需要针对不同的类型找到正确的序列化器,进行序列化工作即可。

??? 对于一个序列化器,通常的工作,是首先取得当前的数据储存容器,然后根据不同的对象类型,将对象输出到outWriter中即可。比如一个序列化实现IntergerSerializer,它的实现如下:

?

?

?


?

?

Java代码??收藏代码
  1. SerializeWriter?out?=?serializer.getWrier();??
  2. ????????Integer?value?=?(Integer)?object;??
  3. ????????out.writeInt(value.intValue());??

?

? ? 这 样即完成了一个完整的序列化工作。当然,对于复杂的数据类型,在实现过程中,可能需要递归地调用JsonSerializer的序列化工作,这得归结于如何处理不同的对象类型了。比如处理一个对象集合时,除需要处理集合本身之外,还需要处理集合中的每一个对象,这时又是一个解析过程。由于使用了同一个jsonSerializer,所以在进行数据处理时,输出的数据会按照在解析过程中的顺序,顺序地写入到outWriter中,这样即保证了数据的正确性。

?

总结

??? 整个解析过程,相对来说,比较地简单。因为,这个解析工作从原理上来讲,也并不复杂。困难地在于,如何处理不同的数据类型,以及在处理过程中如何保证处理的效率。这即是fastjson之所以产生的原因。
??? 本篇从整个结构出发,对fastjson中的json序列化过程有了一个初步的理解,让大家都能够很好地正解fastjson,包括fastjson本身在实现上可能存在的不合理情况。在下一篇中,就效率实现上的两个重要方面(输出效率和解析过程)分别进行解析。

  相关解决方案