Fastjson源码阅读(三):JSON.toJSONString()

  • Post author:
  • Post category:其他




前言

众所周知,我们在应用Fastjson时主要使用的是toJSONString(Object)和parseObject(String, Class)方法。因此接下来将会从这两个方法切入,逐层的分析其实现。

类图



序列化入口

通常使用JSON.toJSONString()这个静态方法来实现序列化。

JSON抽象类实现了JSONAware(转为json串)和JSONStreamAware(将json串写入Appendable)

是JSONObject(内部实现就是个Map)和JSONArray(内部实现是个List)的父类

JSON.toJSONString()方法内部实现基本相同,为做某些特定配置,对外暴露的接口可能不同。

实际交由JSONSerializer类实现



序列化组合器

JSONSerializer类相当于一个序列化组合器,集成了上层调用、序列化配置、具体类型序列化实现、序列化字符串拼接等功能,方便外部统一调用。该类有几个重要的成员:

SerializeConfig、SerializeWriter、各种Filter列表、DateFormat、SerialContext

等,还有每次对各个具体对象序列化ObjectSerializer(非JSONSerializer的成员变量)。



SerializeConfig



功能

SerializeConfig的主要功能是

配置并记录每种Java类型对应的序列化类

(ObjectSerializer接口的实现类),比如Boolean.class使用BooleanCodec(看命名就知道该类将序列化和反序列化实现写到一起了)作为序列化实现类,float[].class使用FloatArraySerializer作为序列化实现类。这些序列化实现类,有的是FastJSON中默认实现的(比如Java基本类),有的是通过ASM框架生成的(比如用户自定义类),有的甚至是用户自定义的序列化类(比如Date类型框架默认实现是转为毫秒,应用需要转为秒)。当然,这就涉及到是使用ASM生成序列化类还是使用JavaBean的序列化类类序列化的问题,这里判断根据就是是否

Android

环境(环境变量”java.vm.name”为”dalvik”或”lemur”就是Android环境),但判断不仅这里一处,后续还有更具体的判断。




实现

SerializeConfig是全局唯一的,它继承自IdentityHashMap,IdentityHashMap是一个长度默认为1024的Hash桶,每个桶存放相同Hash的Entry(可看做链表节点,包含key、value、next指针、hash值)做成的单向链表,IdentityHashMap实现了HashMap的功能,但能避免HashMap并发时的死循环。

哈希桶:哈希桶就是

盛放不同key链表的容器

(即是哈希表),我们可以把每个key的位置看作是一个指针,该指针所指向的位置里放了一个链表,可以认为是指针数组,故该方法也叫开链式。




SerializeWriter

SerializeWriter继承自Java的Writer,其实就是个

专为FastJSON而生的StringBuilder

,完成高性能的字符串拼接。该类成员如下:

  • char buf[]

可理解为每次序列化后字符串的内存存放地址。

  • static ThreadLocal<> bufLocal

每次序列化,都需要重新分配buf[]内存空间。而bufLocal就是每次序列化后buf[]的内存空间保留到ThreadLocal里,但其中的值清空,避免频繁的内存分配和gc。

ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。可能很多朋友都知道ThreadLocal 为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

gc:garbage collection 垃圾回收

  • int features

生成json字符串的特征配置,默认配置为:

<span>QuoteFieldNames | SkipTransientField | WriteEnumUsingToString | SortField</span>

表示含义为:双引号filedName + 忽略transientField + enum类型使用String写入 + 排序输出field。 支持的所有特征在SerializerFeature类中,用户可在调用时显示配置,也可通过JSONFiled或JSONType注入配置。

  • Writer

writer 用户指定将生成的json串直接写入某writer中,比如JSONWriter类。

举例,writeStringWithDoubleQuote()表示用字符串用双引号写入,可以观察拼接字符串的方式。




Filter列表

SerializeWriter中有很多Filter列表,可视为在生成json串的各阶段、各地方定制序列化,大致如下:

  • BeforeFilter :序列化时在最前面添加内容
  • AfterFilter :序列化时在最后面添加内容
  • PropertyFilter :根据PropertyName和PropertyValue来判断是否序列化
  • ValueFilter :修改Value
  • NameFilter :修改key
  • PropertyPreFilter :根据PropertyName判断是否序列化




DateFormat

指定日期格式。若不指定,FastJSON会自动识别如下日期格式:

  • ISO-8601日期格式
  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • 毫秒数值
  • 毫秒字符串
  • .Net Json日期格式
  • new Date()




SerialContext

序列化上下文,在引用或循环引用中使用,该值会放入references的Hash桶(IdentityHashMap)缓存。




ObjectSerializer

ObjectSerializer只有一个接口方法,如下:

void write(JSONSerializer serializer,Objectobject,Object
    fieldName,Type fieldType);

可见,将JSONSerializer传入了ObjectSerializer中,而JSONSerializer有SerializeWriter成员,在每个具体ObjectSerializer实现中,直接使用SerializeWriter拼接字符串即可;Object即是待序列化的对象;fieldName则主要用于组合类引用时设置序列化上下文;而fieldType主要是为了泛型处理。

JSONSerializer中通过public ObjectSerializer getObjectWriter(Class clazz)函数获取类对应的序列化类(即实现ObjectSerializer接口的类),大致逻辑如下:

逻辑

整个过程是先获取已实现基础类对应的序列化类,再通过类加载器获取自定义的AutowiredObjectSerializer序列化类,最后获取通过createJavaBeanSerializer()创建的序列化类。通过该方法会获取两种序列化类,一种是直接的JavaBeanSerializer(根据类的get方法、public filed等JavaBean特征序列化),另一种是createASMSerializer(通过ASM框架生成的序列化字节码),优先使用第二种。选择JavaBeanSerializer的条件为:

  • 该clazz为非public类
  • 该clazz的类加载器在ASMClassLoader的外部,或者clazz就是 Serializable.class,或者clazz就是Object.class
  • JSONType的注解指明不适用ASM
  • createASMSerializer加载失败

结合前面的讨论,可以得出使用ASM的条件:非Android系统、非基础类、非自定义的AutowiredObjectSerializer、非以上所列的使用JavaBeanSerializer条件。

具体基础类的序列化方法、JavaBeanSerializer的序列化方法和ASM生成的序列化方法可以参见代码,这里就不做一一讲解了。



版权声明:本文为weixin_45462807原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。