前言
众所周知,我们在应用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生成的序列化方法可以参见代码,这里就不做一一讲解了。