FastJson是一个近几年非常热门的第三方java库,它以它强大的功能和出色的性能表现而广为人知。那么,究竟为何FastJson能做到如此fast呢?它有什么秘诀?或者说,它做了哪些优化工作使得性能提升如此之多?本文从作者的理解出发,结合代码详细分析FastJson的性能优化方法和优秀的编程实践。
FastJson简介
首先来看看什么是FastJson。引用自github [https://github.com/alibaba/fastjson]:
Fastjson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Fastjson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
简单总结下就是:
1. Fastjson是一个java库集合(server side and android client);
2. Fastjson可以将java对象和JSON字符串来回转换;
Ps. JSON(JavaScript Object Notation, JavaScript对象表示法)是一种轻量级的数据交换格式。
3. Fastjson可以操作任何java对象,即使是一些预先存在的没有源码的对象。
Fastjson用途
Fastjson可以将java对象和JSON字符串来回转换,所以它能被用作:
1. 对象的序列化后存储(memcache, redis等)、传输(web, socket);
2. 接收数据后对象的还原即反序列化。
Fastjson的牛掰之处
几个主流json转换工具的功能性能对比(摘自网络):
几个常用序列化工具的处理速度对比(摘自网络):
从上面两个表的对比数据来看,
1.fastjson性能表现最好,解析速度最快,而且功能已经足够强大,推荐使用;
2.转换对象极其复杂情况下,可以考虑使用gson。
Fastjson提供什么功能/特性以下几点摘自github [https://github.com/alibaba/fastjson]
1. Provide best performance in serverside and android client.
提供服务器端、安卓客户端两种解析工具,性能表现业界最佳。
2. Provide simple toJSONString() andparseObject() methods to convert Java objects to JSON and vice-versa
简单易用,调用toJSONString方法即可将对象转换成json字符串,parseObject方法则反过来将json字符串转换成对象。
3. Allow pre-existing unmodifiableobjects to be converted to and from JSON
允许转换预先存在的无法修改的对象(只有class、无源代码)。
4. Extensive support of Java Generics
Java泛型的广泛支持。
5. Allow custom representations forobjects
允许对象的自定义表示、允许自定义序列化类。
6. Support arbitrarily complexobjects (with deep inheritance hierarchies and extensive use of generic types)
支持任意复杂对象(具有深厚的继承层次和广泛使用的泛型类型)。
Fastjson的性能优化
那么接下来,我们分析下为什么Fastjson能做到这么快。分序列化和反序列化两个过程分析。
序列化
1. IdentityHashMap缓存各种序列化处理类,包括各种基本对象、集合对象、第三方对象、自定义对象,方便序列化处理类的快速查找、避免JavaBeanSerializer的反复创建。
2. 使用ThreadLocal来存储序列化过程中不断append的字符串,减少内存分配和gc,从而提高性能。
3. 用类StringBuilder方式进行字符串操作,配合ThreadLocal实现线程安全的StringBuilder。
4. 缺省启用sort field输出,为deserialize优化做准备。
具体为什么开启了排序的输出能够提升对象还原(反序列化)的效率,请查阅下面反序列化的“快速匹配”。
反序列化
1. IdentityHashMap缓存各种反序列化处理类,包括基本对象、集合对象、第三方对象、自定义对象,方便反序列化类的快速查找、避免JavaBeanDeserializer的反复创建。代码与序列化的处理类缓存相似,具体请参考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java
2. 读取token基于预测。在反序列化一个json字符串时,下一个字符一般情况下是可以预估的。比如字符}之后最有可能出现的是“,”、“]”、“}”或者结束符,有计划、有预测地判断token将能提升不少性能。于是Fastjson在实现的时候写了这样一个函数:
3. 快速匹配。在Fastjson反序列化过程中,有一个非常有用的效率改进方法是有序json的快速匹配。所谓有序json就是json字符串中的key是按照字符排序好了的。上面已经说过,Fastjson的序列化默认是按照key的顺序进行的,因此做反序列化时候,Fastjson采用一种优化算法,就是假设key/value的内容是有序的,读取的时候只需要做key的匹配,而不需要把key从输入中读取出来。通过这个优化,使得Fastjson在处理json文本的时候,少读取超过50%的token,这个是一个十分关键的优化算法。基于这个算法,使用asm实现,性能提升十分明显,超过300%的性能提升。例:{"id":123,"name":"testJson","salary":11}
在上面例子看,虚线标注的三个部分是key,如果key_id、key_name、key_salary这三个key是顺序的,就可以做优化处理,这三个key不需要被读取出来,只需要比较就可以了。
这种算法分两种模式,一种是快速模式,一种是常规模式。快速模式是假定key是顺序的,能快速处理,如果发现不能够快速处理,则退回常规模式。保证性能的同时,不会影响功能。在这个例子中,常规模式需要处理13个token,快速模式只需要处理6个token。实现代码片段如下:
4. 使用asm高效反射
同上序列化的asm反射。
5. symbolTable算法缓存关键字,避免创建新的字符串对象。试想一下,假设一个json字符串中,有成千上万个同样的json对象的数组,那么在转换过程中,如果不对这些json对象中的key做缓存,将会存在成千上万个同样的字符串对象(值相同),显然这样会浪费极大的内存和性能。于是Fastjson写了一个SymbolTable类来缓存这些临时字符串符号变量。
最后
除了性能优化之外,Fastjson还有许多编程思想和实践是值得我们去学习的,只要用心去研究和挖掘,必定能学到很多能够学以致用东西。当然,也只有认真去学习了并尝试在平时项目开发过程中运用,才能够真正提升自己的代码水平。后期有机会再给大家分享下Fastjson在ASM高效反射和泛型支持上的独具匠心之处,请大家拭目以待。J