博客
关于我
fastjson源码--进大厂的最后一脚
阅读量:415 次
发布时间:2019-03-05

本文共 80219 字,大约阅读时间需要 267 分钟。

fastjson源码–进大厂的最后一脚

1.序

记得春招面试的时候的面试官问有读过什么源码没有,自己只是稍微看了一下fastjson的,并且当时最尴尬的是自己对着自己的笔记给面试官读的,然后就顺利的拿下了大厂的offer。所以源码还是值得读的。读源码会让我们有更多的思考在里面,学习的设计思想的魅力。今天就把fastjson整理一下。

2.详细

2.1 JSON

2.1.1 什么是JSON

让我们先来认识一下JSON是什么。以下是百度百科的内容。

在这里插入图片描述
简单来说, Json是一种轻量级的数据交换格式,采用一种“键:值”对的文本格式来存储和表示数据,在系统交换数据过程中常常被使用,是一种理想的数据交换语言。在使用Java做Web开发时,不可避免的会遇到Json的使用。

2.1.2 JSON形式与语法

{   	"ID": 1002,	"name": "张三",	"age": 21}

1:数据在花括号中

2:数据以"键:值"对的形式出现(其中键多以字符串形式出现,值可取字符串,数值,甚至其他json对象)
3:每两个"键:值"对以逗号分隔(最后一个"键:值"对省略逗号)
遵守上面3点,便可以形成一个json对象。

2.1.3 JSON对象数组

[	{   "ID": 1, "name": "张三", "ae": 4},	{   "ID": 2, "name": "李四", "ae": 5},	{   "ID": 3, "name": "王五", "ae": 2}]

1:数据在方括号中(可理解为数组)

2:方括号中每个数据以json对象形式出现
3:每两个数据以逗号分隔(最后一个无需逗号)
遵守上面3点,便可形成一个json对象数组(及一个数组中,存储了多个json对象)
理解了上面两种基本的形式,我们就可以得出其他的数据形式,例如下面这个:

{   	"部门":"研发部",	"成员":[	{   "ID": 1001, "name": "张三", "age": 24},	{   "ID": 1002, "name": "李四", "age": 25},	{   "ID": 1003, "name": "王五", "age": 22}],	"部门位置":"111号"}

2.1.4 JSON字符串

JSON字符串也是在平时开发中使用较多的,json字符串应满足以下条件:

1:它必须是一个字符串,由" "或者’ '包裹数据,支持字符串的各种操作
2:里面的数据格式应该要满足其中一个格式,可以是json对象,也可以是json对象数组或者是两种基本形式的组合变形。

var str = ‘{ “name”: “mady”, “age”: 24 }’;

2.1.5 总

总结:json可以简单的分为基本形式:json对象,json对象数组。两种基本格式组合变形出其他的形式,但其本质还是json对象或者json对象数组中的一种。json对象或对象数组可以转化为json字符串,使用于不同的场合。

2.2 (Jackson,Gson,Fastjson)的对比

2.2.1热度

FastJson

https://github.com/alibaba/fastjson
在这里插入图片描述

Jackson

https://github.com/FasterXML/jackson
在这里插入图片描述

Gson

https://github.com/google/gson
在这里插入图片描述

json-lib

2.2.2对比(有待修改)

阿里巴巴的FastJson

Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。
无依赖,不需要例外额外的jar,能够直接跑在JDK上。
FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,导致Json转换出错,需要制定引用。
FastJson采用独创的算法,将parse的速度提升到极致,超过所有json库。
开源的Jackson
相比json-lib框架,Jackson所依赖的jar包较少,简单易用并且性能也要相对高些。
而且Jackson社区相对比较活跃,更新速度也比较快。
Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。
Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式
Google的Gson
Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,
但自从在2008年五月公开发布第一版后已被许多公司或用户应用。
Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不需要例外额外的jar,能够直接跑在JDK上。
而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。
类里面只要有get和set方法,Gson完全可以将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。
Gson在功能上面无可挑剔,但是性能上面比FastJson有所差距。
json-lib
json-lib最开始的也是应用最广泛的json解析工具,json-lib 不好的地方确实是依赖于很多第三方包,
包括commons-beanutils.jar,commons-collections-3.2.jar,commons-lang-2.6.jar,commons-logging-1.1.1.jar,ezmorph-1.0.6.jar,
对于复杂类型的转换,json-lib对于json转换成bean还有缺陷,比如一个类里面会出现另一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。
json-lib在功能和性能上面都不能满足现在互联网化的需求。

fastjson是目前java语言中最快的json库,比自称最快的jackson速度还要快,第三方独立测试结果看这里:

https://github.com/eishay/jvm-serializers/wiki。

2.3 fastjson

2.3.1来源

FastJson

https://github.com/alibaba/fastjson
maven中央仓库
http://central.maven.org/maven2/com/alibaba/fastjson/
Sourcefor ge.net
https://sourceforge.net/projects/fastjson/files/
在maven项目的pom文件中直接配置fastjson依赖
fastjson最新版本都会发布到maven中央仓库,你可以直接依赖。

com.alibaba
fastjson
x.x.x

下面是fastjson的源码

在这里插入图片描述

2.3.2 Fastjson主要的类和API

在包中,可以发现主要的3个类,JSON,JSONArray,JSONObject。三者之间的关系如下,JSONObject和JSONArray继承JSON。

可以发现,

JSONObject代表json对象
JSONArray代表json对象数组
JSON代表JSONObject和JSONArray的转化

可以发现,JSONObject代表json对象,JSONArray代表json对象数组,JSON代表JSONObject和JSONArray的转化。

Fastjson的主要入口类是com.alibaba.fastjson.JSON 主要的API是JSON.toJSONString 和parseObject。

在这里插入图片描述

序列化

String jsonString = JSON.toJSONString(obj);
反序列化:
VO vo = JSON.parseObject("…", VO.class);
泛型反序列化:
import com.alibaba.fastjson.TypeReference; List list = JSON.parseObject("…", new TypeReference<List>() {});

2.3.3 源码解析

2.3.3.1 JSONObject

在这里插入图片描述

观察该类的继承与实现关系,不难发现,JSONObject实现了Map接口,而json对象中的数据都是以"键:值"对形式出现,可以猜想,JSONObject底层操作是由Map实现的。

类中主要是get()方法。因为JSONObject相当于json对象,所以该类中主要封装了各种get方法,通过"键:值"对中的键来获取其对应的值。且方法的输入参数几乎皆为String类型,这是因为json对象中,"键:值"对的键都是String类型的。来看一下平时用到较多的 。

1 getString(String key)

getString(String key)方法,该方法输入参数为String key(键),输出为String ,用于获取json对象中的字符串型数据。例如通过该方法获取 “name”:"bob"键值对中name这个键所对应的值bob。

在这里插入图片描述

在这里插入图片描述

发现内部主要由Map接口中的get()方法实现。

2.getInteger(String key)
再去看JSONObject中另一个常用的方法getInteger(String key),该方法获取json对象中的整型数据,例如获取"age:20"键值对中age对应的整型数值20.
在这里插入图片描述

对比getString(String key)方法,两者极为相似,都是通过Map接口的get()方法实现。

3.其它
在这里插入图片描述

总结:JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。

2.3.3.2 JSONArray

在这里插入图片描述

观察JSONArray的继承与实现,并结合上面对JSONObject的分析,不难发现,其内部是由List接口中的方法来完成操作的。

同样观察JSONArray类中的方法,由于方法较多,下面分为两部分

JSONArray代表json对象数组,json数组对象中存储的是一个个json对象,所以类中的方法主要用于直接操作json对象。比如这其中的add(),remove(),containsAll()方法,对应于json对象的添加,删除与判断。其内部主要有List接口中的对应方法来实现。

在这里插入图片描述

跟JSONObject一样,JSONArray里面也有一些get()方法,不过都不常用,最有用的应该是getJSONObject(int index)方法,该方法用于获取json对象数组中指定位置的JSONObject对象,配合size()方法,可用于遍历json对象数组中的各个对象。

接下来

在这里插入图片描述

在这里插入图片描述

通过以上两个方法,在配合for循环,即可实现json对象数组的遍历,当然JSONArray中也实现了迭代器方法来遍历,这和List的遍历极为相似。

在这里插入图片描述

通过遍历得到JSONObject对象,然后再利用JSONObject类中的get()方法,即可实现最终json数据的获取!!!

2.3.3.3 JSON类

最后一个,也是最重要的一个类JSON类。之所以把这个放在最后,是因为这个类主要是实现转化用的,最后的数据获取,还是要通过上面的JSONObject和JSONArray来实现。

在这里插入图片描述

在这里插入图片描述

仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。

1 toJSONString ()

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

该方法经过多次重载,但最终都是实现json对象转化为json字符串和javabean对象转化为json 字符串。其中,有关键字transient修饰的toJSONString()用于json对象序列化过程中,希望某个"键:值"对数据不变的应用中。

2 parseObject()

JSON类之parseObject()方法,实现json字符串转换为json对象或javabean对象

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

该方法返回JSONObject对象,用于实现json字符串向json对象的转化,其内部调用了parse()方法,调用底层的DefaultJSONParser解析类进行转化,在转化失败时,抛出can not cast to JSONObject异常。

该方法不仅能实现json字符串向json对象的转化,经过重载之后,还能实现json字符串向javabean对象的转化

使用

json字符串与javaBean之间的转换可以使用 TypeReference 这个类,也可以使用Class这个类。

Student stu1=JSON.parseObject(jsonstr,new TypeReference(){});

Student stu1=JSON.parseObject(jsonstr,Student.class);

我推荐使用第二种Class类反射来实现,比较简单。

JSON类之JSONArray()方法,实现json字符串转化为json对象数组或List

与parseObject()方法类似,parseArray()将json字符串转化为json对象数组或转化成包含泛型的List

在这里插入图片描述

在这里插入图片描述
JSON类之toJSON()方法,实现javabean对象转化为json对象

该方法用的比较少,主要用于将javabean对象转化为json对象,内部通过Map,LinkedHashMap,HashMap等集合接口实现。

在这里插入图片描述

在这里插入图片描述
该方法也经过重载,通过TypeReference类和Class类反射来实现,主要讲json对象转化为javabean对象,用的也比较少。

在这里插入图片描述

2.3.4 将对象中的空值输出

在fastjson中,缺省是不输出空值的。无论Map中的null和对象属性中的null,序列化的时候都会被忽略不输出,这样会减少产生文本的大小。但如果需要输出空值怎么做呢?

如果你需要输出空值,需要使用 SerializerFeature.WriteMapNullValue

Model obj = …;

JSON.toJSONString(obj, SerializerFeature.WriteMapNullValue);

class Model {

public List items;
}
在这里插入图片描述

Model obj = …;

String text = JSON.toJSONString(obj, SerializerFeature.WriteNullBooleanAsFalse);

2.3.5 Fastjson 处理日期

常规

JSON.toJSONStringWithDateFormat(date, “yyyy-MM-dd HH:mm:ss.SSS”);

使用ISO-8601日期格式

JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);

全局修改日期格式

JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);

反序列化能够自动识别如下日期格式:

ISO-8601日期格式

  • yyyy-MM-dd

  • yyyy-MM-dd HH:mm:ss

  • yyyy-MM-dd HH:mm:ss.SSS

  • 毫秒数字

  • 毫秒数字字符串

  • .NET JSON日期格式

  • new Date(198293238)

public static void main(String[] args) {           Student student = new Student();        student.setDate(new Date());        // 序列化        String jsonString = JSON.toJSONString(student);        System.out.println("序列化:" + jsonString);        // 序列化处理时间,方式一        jsonString = JSON.toJSONStringWithDateFormat(student, "yyyy-MM-dd HH:mm:ss.SSS");        System.out.println("序列化处理时间,方式一:" + jsonString);        // 序列化处理时间,方式二:ISO-8601日期格式        jsonString = JSON.toJSONString(student, SerializerFeature.UseISO8601DateFormat);        System.out.println("序列化处理时间,方式二:ISO-8601日期格式:" + jsonString);        // 序列化处理时间,方式三:全局修改日期格式        JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";        jsonString = JSON.toJSONString(student, SerializerFeature.WriteDateUseDateFormat);        System.out.println("序列化处理时间,方式三:全局修改日期格式:" + jsonString);}

2.3.6 Fastjson 定制序列化

简介

fastjson支持多种方式定制序列化。
通过@JSONField定制序列化
通过@JSONType定制序列化
通过SerializeFilter定制序列化
通过ParseProcess定制反序列化

2.3.6.1使用@JSONField配置

1、JSONField 注解介绍#

package com.alibaba.fastjson.annotation;public @interface JSONField {       // 配置序列化和反序列化的顺序,1.1.42版本之后才支持    int ordinal() default 0;     // 指定字段的名称    String name() default "";    // 指定字段的格式,对日期格式有用    String format() default "";    // 是否序列化    boolean serialize() default true;    // 是否反序列化    boolean deserialize() default true;}

2、JSONField配置方式

可以把@JSONField配置在字段或者getter/setter方法上,例如:
配置在字段上

public class VO {        @JSONField(name="ID")     private int id;     @JSONField(name="birthday",format="yyyy-MM-dd")     public Date date;}

配置在 Getter/Setter 上

public class VO {       private int id;    @JSONField(name="ID")    public int getId() {    return id;}    @JSONField(name="ID")    public void setId(int id) {   this.id = id;}}

注意:若属性是私有的,必须有set*方法。否则无法反序列化。

3、使用format配置日期格式化
可以定制化配置各个日期字段的格式化

public class A {         // 配置date序列化和反序列使用yyyyMMdd日期格式      @JSONField(format="yyyyMMdd")      public Date date; }

4、使用serialize/deserialize指定字段不序列化

public class A {         @JSONField(serialize=false)      public Date date; } public class A {         @JSONField(deserialize=false)      public Date date; }

5、使用ordinal指定字段的顺序

缺省Fastjson序列化一个java bean,是根据fieldName的字母序进行序列化的,你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。

public static class VO {       @JSONField(ordinal = 3)    private int f0;    @JSONField(ordinal = 2)    private int f1;    @JSONField(ordinal = 1)    private int f2;}

6、使用serializeUsing制定属性的序列化类

在fastjson 1.2.16版本之后,JSONField支持新的定制化配置

serializeUsing,可以单独对某一个类的某个属性定制序列化,比如:public static class Student{       @JSONField(serializeUsing = ModelValueSerializer.class)    public int value;}public static class ModelValueSerializer implements ObjectSerializer {       @Override    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,                      int features) throws IOException {           Integer value = (Integer) object;        String text = id+ "号";        serializer.write(text);    }}

测试代码

Student student= new Student();student.id= 100;String json = JSON.toJSONString(student);Assert.assertEquals("{\"value\":\"100号\"}", json);

2.3.6.2使用@JSONType配置

和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上。

SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter,用于不同场景的定制序列化。

PropertyPreFilter 根据PropertyName判断是否序列化
和PropertyFilter不同只根据object和name进行判断,在调用getter之前,这样避免了getter调用可能存在的异常。
public interface PropertyPreFilter extends SerializeFilter {

boolean apply(JSONSerializer serializer, Object object, String name);  }

PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化

public interface PropertyFilter extends SerializeFilter {       boolean apply(Object object, String propertyName, Object propertyValue); }

可以通过扩展实现根据object或者属性名称或者属性值进行判断是否需要序列化。例如

PropertyFilter filter = new PropertyFilter() {       public boolean apply(Object source, String name, Object value) {           if ("id".equals(name)) {               int id = ((Integer) value).intValue();            return id >= 100;        }        return false;    }};

JSON.toJSONString(obj, filter); // 序列化的时候传入filter

NameFilter 修改Key
如果需要修改Key,process返回值则可

public interface NameFilter extends SerializeFilter {       String process(Object object, String propertyName, Object propertyValue);}

fastjson内置一个PascalNameFilter,用于输出将首字符大写的Pascal风格。 例如:

public static void main(String[] args) {               Student student = new Student();            student.setId(9L);            student.setName("你好");            String jsonString = JSON.toJSONString(student);             // 序列化的时候传入filter            System.out.println("普通序列化:" + jsonString + "\n");            NameFilter filter = new NameFilter() {                   @Override                public String process(Object object, String name, Object value) {                       System.out.println("----------------object=" + object);                    System.out.println("----------------name=" + name);                    System.out.println("----------------value=" + value);                    System.out.println("");                    // 属性是id是修改id的名字                    if ("id".equals(name)) {                           return name + "$";                    }                    return name;                }            };            jsonString = JSON.toJSONString(student, filter);            // 序列化的时候传入filter            System.out.println("NameFilter序列化:" + jsonString + "\n");            // fastjson内置一个PascalNameFilter,用于输出将首字符大写的Pascal风格            jsonString = JSON.toJSONString(student, new PascalNameFilter());            // 序列化的时候传入filter            System.out.println("PascalNameFilter序列化:" + jsonString + "\n");        }

ValueFilter 修改Value

ValueFilter 接口:

public interface ValueFilter extends SerializeFilter {         Object process(Object object, String propertyName, Object propertyValue);  }

如果需要修改Value,process返回值则可,例如:

public static void main(String[] args) {               Student student = new Student();            student.setId(9L);            student.setName("你好");            String jsonString = JSON.toJSONString(student);             // 序列化的时候传入filter            System.out.println("普通序列化:" + jsonString + "\n");            ValueFilter filter = new ValueFilter() {                   @Override                public Object process(Object object, String name, Object value) {                       System.out.println("----------------object=" + object);                    System.out.println("----------------name=" + name);                    System.out.println("----------------value=" + value);                    System.out.println("");                    // 属性是id时修改id的值                    if ("id".equals(name)) {                           long id = ((Long) value).longValue();                        return id + "0";                    }                    return value;                }            };            jsonString = JSON.toJSONString(student, filter);            // 序列化的时候传入filter            System.out.println("ValueFilter序列化:" + jsonString + "\n");        }

BeforeFilter 序列化时在最前添加内容

BeforeFilter 接口:

public abstract class BeforeFilter implements SerializeFilter {         protected final void writeKeyValue(String key, Object value) {    ... }      // 需要实现的抽象方法,在实现中调用writeKeyValue添加内容      public abstract void writeBefore(Object object);  }

在序列化对象的所有属性之前执行某些操作,例如调用 writeKeyValue 添加内容:

public static void main(String[] args) {               Student student = new Student();            student.setId(9L);            student.setName("你好");            String jsonString = JSON.toJSONString(student);             // 序列化的时候传入filter            System.out.println("普通序列化:" + jsonString + "\n");            BeforeFilter filter = new BeforeFilter() {                   @Override                public void writeBefore(Object object) {                       System.out.println("----------------object=" + object);                    Student student = (Student) object;                    System.out.println("----------------User.id=" + student.getId() + " " + "User.name=" + student.getName() + "\n");                    student.setName(student.getName() + "$$$");                }            };            jsonString = JSON.toJSONString(student, filter);            // 序列化的时候传入filter            System.out.println("BeforeFilter序列化:" + jsonString + "\n");        }

AfterFilter 序列化时在最后添加内容

AfterFilter 接口:

public abstract class AfterFilter implements SerializeFilter {         protected final void writeKeyValue(String key, Object value) {    ... }      // 需要实现的抽象方法,在实现中调用writeKeyValue添加内容      public abstract void writeAfter(Object object);  }

在序列化对象的所有属性之后执行某些操作,例如调用 writeKeyValue 添加内容,例如:

public static void main(String[] args) {               Student student = new Student();            student.setId(9L);            student.setName("你好");            String jsonString = JSON.toJSONString(student);             // 序列化的时候传入filter            System.out.println("普通序列化:" + jsonString + "\n");            AfterFilter filter = new AfterFilter() {                   @Override                public void writeAfter(Object object) {                       Student student = (Student) object;                    System.out.println("------------Student.id=" + student.getId() + " " + "Student.name=" + student.getName() + "\n");                    student.setName(student.getName() + "$$$");                }            };            jsonString = JSON.toJSONString(student, filter);            // 序列化的时候传入filter            System.out.println("AfterFilter序列化:" + jsonString + "\n");            jsonString = JSON.toJSONString(student, filter);            // 序列化的时候传入filter            System.out.println("BeforeFilter序列化:" + jsonString + "\n");        }

2.3.7 简单的例子

在这里插入图片描述

2.3.3.1 JSON字符串和JavaBean对象互转

import lombok.Data;import java.util.ArrayList;import java.util.List;@Datapublic class Student {       private Long id;    private String name;    private List
users = new ArrayList
(); public void addStudent(Student student) { users.add(student); }}public class Main { public static void main(String[] args) { Student student = new Student(); student.setId(2L); student.setName("guest"); // 转换为 JSON String jsonString = JSON.toJSONString(student); System.out.println("JSON字符串:" + jsonString); // 转换为 对象BEAN Student student1 = JSON.parseObject(jsonString, Student.class); System.out.println("JavaBean对象:" + student1); }}

2.3.3.2 JSON字符串转JSON对象

public class Main1 {       public static void main(String[] args) {           String s ="{\"student\":\"study\",\"id\":\"1\",\"ordinal\":8,\"organUnitFullName\":\"testJSON\",\"parent\":\"0\",\"suborderNo\":\"58961\"}";        JSONObject jsonObject = JSON.parseObject(s);        String study = jsonObject.getString("student");        String id = jsonObject.getString("id");        System.out.println("study ="+study);        //add        System.out.println("id ="+id);        //1        System.out.println("jsonObject ="+jsonObject);        //action =add        //id =1    }}

2.3.3.3 JSON字符串数组类型与JAVA对象互转

{   	"errors":		[			{   				"code": "UUM70004",				"message": "名称不能为空",				"data": {   					"id": "254",					"name": "liu",				},				"success": false			}, {   				"code": "UUM70004",				"message": "名称不能为空",				"data": {   					"id": "255",					"name": "liu",				},				"success": false			}		]}
public static void main(String[] args) {           //json字符串--数组型与JSONArray对象之间的转换        String str = "{\"errors\":[{\"code\":\"UUM70004\",\"message\":\"名称不能为空\",\"data\":{\"id\":\"254\",\"name\":\"liu\"},\"success\":false},{\"code\":\"UUM70004\",\"message\":\"名称不能为空\",\"data\":{\"id\":\"255\",\"name\":\"liu\"},\"success\":false}]}";        JSONObject jsonObject = JSON.parseObject(str);        JSONArray error = jsonObject.getJSONArray("errors");        List
errors = JSON.parseObject(error.toJSONString(), new TypeReference
>() { }); for (ErrEor e: errors) { //Error的属性 System.out.println("Error属性="+e.getSuccess()); System.out.println("Error属性="+e.getCode()); System.out.println("Error属性="+e.getMessage()); //Error集合属性 List
datas = e.getData(); for (Data d: datas) { System.out.println("data对象属性=" + d.getId()); System.out.println("data对象属性=" + d.getName()); } } }

2.3.3.4 JAVA对象转JSON对象

//javabean转json对象    public static void main(String[] args) {           Student student = new Student();        student.setName("liu");        student.setId(2L);        JSONObject jsonObj = (JSONObject) JSON.toJSON(student);        JSON json = (JSON) JSON.toJSON(student);        System.out.println("jsonObj"+jsonObj);        System.out.println("json对象"+json);    }

2.3.3.5 总结

(1)对于JSON对象与JSON格式字符串的转换可以直接用 toJSONString()这个方法。

(2)javaBean与JSON格式字符串之间的转换要用到:JSON.toJSONString(obj);
(3)javaBean与json对象间的转换使用:JSON.toJSON(obj),然后使用强制类型转换,JSONObject或者JSONArray。

2.3.8 序列化和反序列化源码详解

序列化是通过某种算法将存储于内存中的对象转换成可以用于持久化存储或者通信的形式的过程

反序列化是将这种被持久化存储或者通信的数据通过对应解析算法还原成对象的过程,它是序列化的逆向操作

1为什么需要序列化

前端请求后端接口数据的时候,后端需要返回 JSON 数据,这就是后端将 Java 堆中的对象序列化为了 JSON 数据传给前端,前端可以根据自身需求直接使用或者将其反序列化为 JS 对象。

2怎么序列化
(1)将对象实例相关的类元数据输出。
(2)递归地输出类的超类描述直到不再有超类。
(3)类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
(4)从上至下递归输出实例的数据
3 JDK类库中序列化反序列化
序列化
步骤一:创建一个对象输出流,它可以包装一个其它类型的目标输出流,如文件输出流:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“D:\object.out”));
步骤二:通过对象输出流的writeObject()方法写对象:
oos.writeObject(new User(“xuliugen”, “123456”, “male”));
反序列化
步骤一:创建一个对象输入流,它可以包装一个其它类型输入流,如文件输入流:
ObjectInputStream ois= new ObjectInputStream(new FileInputStream(“object.out”));
步骤二:通过对象输出流的readObject()方法读取对象:
User user = (User) ois.readObject();
说明:为了正确读取数据,完成反序列化,必须保证向对象输出流写对象的顺序与从对象输入流中读对象的顺序一致。

2.3.8.1 序列化过程

在这里插入图片描述

fastjson核心功能包括序列化和反序列化,序列化的含义是将java对象转换成跨语言的json字符串。

在这里,需要考虑的主要有两个部分,一是临时保存在序列化过程中用于储存数据的容器,二是处理对象序列化的序列化器。

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

SerializeWriter数据保存器(序列化输出容器)

com.alibaba.fastjson.serializer.SerializeWriter类非常重要,序列化输出都是通过转换底层操作,

在这里插入图片描述

继承了Writer类,实现了输出字符的基本功能,并且提供了拼接数据的基本功能。内部使用了一个buf数组和count来进行计数。这个类的实现结果和StringBuilder的工作模式差不多。但我们说为什么不使用StringBuilder,主要是因为StringBuilder没有针对json序列化提出更加有效率的处理方式,而且单就StringBuilder而言,内部是为了实现字符串拼接而生,因为很自然地使用了更加能够读懂的方式进行处理。相比,serializeWriter单处理json序列化数据传输,功能单一,因此在某些方面更加优化一些。

SerializeWriter是一个用于储存在序列化过程中产生的数据信息,它与jdk中的StringBuiler有着类似的功能,即将不同的数据填充到此容器中。之所以不使用StringBuilder的原因之一在于StringBuilder没有提供一些特别为性能优化的方法,并且StringBuilder在处理过程中增加了多余的操作(如新分配对象)。该容器的主要功能就是接收不同的数据,并将这些数据存储到该内部的一个字符数组当中,同时记录字符总数。

既然充当了一个数据输出的角色,那么就可以往其中输入任何的数据,包括int,byte,short等基本类型和对应的包装类型,也包括日期数据,以及经常使用的字符串数据等。对于在这些数据类型之外的其它类型,由于json的特殊结构,所有的高级类型均可以转化于这些基础类型的组织体,所以不需要再针对高级类型作处理了(这些是序列化器应该考虑的问题)。

在这里插入图片描述

方法总共可以分五个部分,
1.第一个部分是针对writer基本功能一个扩展,即支持输出int,字符,以及字符数组,追加字符数组(包括字符串)等;
2.第二个部分提供了写整形和长整形的基本方法;
3.第三个部分是提供写基本数据类型数组的支持;
4.第四个部分是提供写一个数字+一个字符的形式,比如数据+[,],}]这种格式;第五个部分是提供写数据串,主是是针对字符串追加双引号或单引号(以支持标准json)。
5.五个部分的方法,每个部分都有其特殊的作用和意义,针对最常用的数字和字符串作了特别的对待。
在实现上面,SerializeWriter使用了一个内部的字符数组作为数据的储存器,同时使用了一个计数器计算当前存储的字符量。既然使用了字符数组,那么肯定有相关的操作,如字符扩容等。整个写数据的过程,其实就是往这个字符数组追加数据的过程,需要考虑只是如何追加数据的问题,即上面所列出的这么多些方法。在最终写完数据之后,即可将这个字符数组转为我们所需要的字符串了。

源码

/**     * @since 1.2.9     * @param writer     * @param defaultFeatures     * @param features     */    protected char                           buf[];    /**     * 储存序列化结果的字段     */    protected int                            count;    /**     * 写入缓存的长度     */    private final static ThreadLocal
bufLocal = new ThreadLocal
(); /** * 该对象用于close时将buf绑定到线程上,避免下次重复new出 */ protected int features; /** * 序列化的一些特性配置 */ private final Writer writer; /** * 包装对象,支持对Writer类型包含数据的序列化 */ //传入Writer对象 public SerializeWriter(Writer writer, int defaultFeatures, SerializerFeature... features){ this.writer = writer; buf = bufLocal.get(); //获取线程缓存buf对象 if (buf != null) { bufLocal.set(null); } else { buf = new char[2048]; } //获取到赋值给当前buf并清空,防止重复new出。 //由于count在关闭的时候已经等于0,所以即使buf里有数据,也不会影响当次结果 int featuresValue = defaultFeatures; //默认序列化属性 for (SerializerFeature feature : features) { featuresValue |= feature.getMask(); } this.features = featuresValue; computeFeatures(); }

在类声明中,这里有一个优化措施(笔者最开始未注意到,经作者指出之后才明白)。即是对buf数组的缓存使用,即在一次处理完毕之后,储存的数据容器并不销毁,而是留在当前线程变量中。以便于在当前线程中再次序列化json时使用。源码如下:

public SerializeWriter(){           buf = bufLocal.get(); // new char[1024];        if (buf == null) {               buf = new char[1024];        } else {               bufLocal.set(null);        }    }

在初始构造时,会从当前线程变量中取buf数组并设置在对象属性buf中。而在每次序列化完成之后,会通过close方法,将此buf数组再次绑定在线程变量当中,如下所示:

/**     * Close the stream. This method does not release the buffer, since its contents might still be required. Note:     * Invoking this method in this class will have no effect.     */    public void close() {           bufLocal.set(buf);    }

当然,buf重新绑定了,肯定计数器count应该置0。这是自然,count是对象属性,每次在新建时,自然会置0。

在实现过程当中,很多具体的实现是借鉴了StringBuilder的处理模式的,在以下的分析中会说到。

存在buf的缓存对象,自然需要具体的写入方法。下图列出了主要的写入方法

在这里插入图片描述

总结
SerializeWriter主要实现了五个方面的输出内容。
1,提供writer的基本功能,输出字符,输出字符串
2,提供对整形和长整形输出的特殊处理
3,提供对基本类型数组输出的支持
4,提供对整形+字符的输出支持
5,提供对字符串+双(单)引号的输出方式
五个方面主要体现在不同的作用域。
1,第一个提供了最基本的writer功能,以及在输出字符上最基本的功能,即拼接字符数组(不是字符串);
2,第二个针对最常用的数字进行处理;
3,第三个,针对基本类型数组类处理;
4,第四个针对在处理集合/数组时,最后一位的特殊处理,联合了输出数字和字符的双重功能,效率上比两个功能的实现原理上更快一些;
5,第五个,针对字符串的特殊处理(主要是特殊字符处理)以及在json中,字符串的引号处理(即在json中,字符串必须以引号引起来)。
实现思想
数据输出最后都变成了拼接字符的功能,即将各种类型的数据转化为字符数组的形式,然后将字符数组拼接到buf数组当中。这中间主要逻辑如下:
1 对象转化为字符数组
2 准备装载空间,以容纳数据
2.1 计数器增加
2.2 扩容,字符数组扩容
3 装载数据
4 计数器计数最新的容量,完成处理
这里面主要涉及到一个buf数组扩容的概念,其使用的扩容函数expandCapacity其内部实现和StringBuilder中一样。即(当前容量 + 1)* 2,具体可以见相应函数或StringBuilder.ensureCapacityImpl函数。

JsonSerializer( 对象序列化入口)

在这里插入图片描述

JsonSerializer,准备地讲,这个类不应该叫这个名字,因为它与其它的对象序列化器相混淆了。这只是一个提供对象序列化的一个入口;同时,它持有所有具体负责对象序列化工作类的引用。将这些序列化器集中起来,需要用到哪个对象序列化器时,就取出这个序列化器,并调用相应的序列化方法。

既然是对象序列化入口,它就需要关注两个事情。一是我们究竟有哪些序列化器可以使用,二是对于一个对象,应该使用哪一个序列化器来进行工作。对于这两个问题,JsonSerializer内部持有一个JSONSerializerMap的属性,即表示应该序列化的对象类型和对应的序列化器的一个映射。我们来看默认的构造方法,它使用了默认的全局对象类型和对象序列化器映射:

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

Class<?> clazz = object.getClass();

ObjectSerializer writer = getObjectWriter(clazz);
writer.write(this, object);

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

Write

正如上面所说,进入序列化工作之后,即是针对每一种类型进行序列化处理了。该序列化工作使用了统一的方法,即实现了统一的序列化方法:
void write(JSONSerializer serializer, Object object) throws IOException

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

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

SerializeWriter out = serializer.getWrier();

Integer value = (Integer) object;
out.writeInt(value.intValue());

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

具体序列化过程

关键步骤

1 SerializeWriter out = new SerializeWriter();
//和StringBuilder 一样,并且在存储过程中进行了性能优化(数据保持器)
2 JSONSerializer serializer = new JSONSerializer(out);
//提供一个对象序列化的入口
//哪些序列化器可以使用
//对于一个对象应该使用哪一个来进行序列化
3 serializer.write(object)
//调用序列化方法序列化对象,产生JSON字符串信息
4 return out.toString();
//返回JSON

从调用方法toJSONString开始,会调用

public static final String toJSONString(Object object, SerializerFeature... features) {           SerializeWriter out = new SerializeWriter();        //详细写数据的类,存储序列化过程的数据,最后通过 out.toString()转化为json字符串        try {               JSONSerializer serializer = new JSONSerializer(out);            //Json序列化解析对象的类,解析过程中向out写入数据            serializer.getPropertyFilters().add(new PropertyFilter() {                                   public boolean apply(Object source, String name, Object value) {                       if ("id".equals(name)) {                           return false;                    }                    return true;                }            });            serializer.getNameFilters().add(new NameFilter() {                   public String process(Object source, String name, Object value) {                       if ("v".equals(name)) {                           return "value";                    }                    return name;                }                            });            serializer.getValueFilters().add(new ValueFilter() {                                   public Object process(Object source, String name, Object value) {                       if ("v".endsWith(name)) {                           return "xxx";                    }                                        return value;                }            });            for (com.alibaba.fastjson.serializer.SerializerFeature feature : features) {                   //向解析器添加序列化属性                serializer.config(feature, true);            }            serializer.write(object);            //解析传入的对象,保存在out中            return out.toString();            //将解析的结果转成String输出        } catch (StackOverflowError e) {               throw new JSONException("maybe circular references", e);        } finally {               out.close();        }}

接下里我们来看JSONSerializer的write方法

/**    * @Description    * 这个序列化方法实际并不是真正执行序列化操作,首先做序列化特性配置,    * 然后追加序列化拦截器,开始执行序列化对象操作委托给了config对象查找。    * 我们继续进入serializer.write(object) 查看:    */public final void write(Object object) {           //如果空对象,直接写入null字符串Z        if (object == null) {               out.writeNull();            return;        }        Class
clazz = object.getClass(); ObjectSerializer writer = getObjectWriter(clazz); //获取到类,通过getObjectWriter(clazz)找到对应的解析器 try { writer.write(this, object, null, null, 0); //对应序列化器执行序列化写操作 } catch (IOException e) { throw new JSONException(e.getMessage(), e); }}

那我们来看看怎么获取对应序列化器的

* 内部又调用com.alibaba.fastjson.serializer.SerializeConfig#     * getObjectWriter(java.lang.Class < ? >, boolean),这个类实现相对复杂了一些,     * 我会按照代码顺序梳理所有序列化实例的要点 :     *     * 查找具体序列化实例,查找方法基本思想根据class类型或者实现接口类型进行匹配查找。     * 接下来针对逐个序列化实现依次分析。	 */	public ObjectSerializer getObjectWriter(Class
clazz, boolean create) { /** 首先从内部已经注册查找特定class的序列化实例 */ ObjectSerializer writer = get(clazz); //如果未获取到,再解析对象类型,并加入配置列表当中,例如 if (writer == null) { try { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); /** 使用当前线程类加载器 查找 META-INF/services/AutowiredObjectSerializer.class实现类 */ for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) { if (!(o instanceof AutowiredObjectSerializer)) { continue; } AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o; for (Type forType : autowired.getAutowiredFor()) { //如果存在,注册到内部serializers缓存中 put(forType, autowired); } } } catch (ClassCastException ex) { // skip } writer = get(clazz); } if (writer == null) { final ClassLoader classLoader = JSON.class.getClassLoader(); /** 使用加载JSON类的加载器 查找 META-INF/services/AutowiredObjectSerializer.class实现类 */ if (classLoader != Thread.currentThread().getContextClassLoader()) { try { for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) { if (!(o instanceof AutowiredObjectSerializer)) { continue; } AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o; for (Type forType : autowired.getAutowiredFor()) { //如果存在,注册到内部serializers缓存中 put(forType, autowired); } } } catch (ClassCastException ex) { // skip } //尝试在已注册缓存找到特定class的序列化实例 writer = get(clazz); } } for (Module module : modules) { writer = module.createSerializer(this, clazz); if (writer != null) { put(clazz, writer); return writer; } } if (writer == null) { String className = clazz.getName(); Class
superClass; if (Map.class.isAssignableFrom(clazz)) { //如果class实现类Map接口,使用MapSerializer序列化 put(clazz, writer = MapSerializer.instance); } else if (List.class.isAssignableFrom(clazz)) { //如果class实现类List接口,使用ListSerializer序列化 put(clazz, writer = ListSerializer.instance); } else if (Collection.class.isAssignableFrom(clazz)) { //如果class实现类Collection接口,使用CollectionCodec序列化 put(clazz, writer = CollectionCodec.instance); } else if (Date.class.isAssignableFrom(clazz)) { //如果class继承Date,使用DateCodec序列化 put(clazz, writer = DateCodec.instance); } else if (JSONAware.class.isAssignableFrom(clazz)) { //如果class实现类JSONAware接口,使用JSONAwareSerializer序列化 put(clazz, writer = JSONAwareSerializer.instance); } else if (JSONSerializable.class.isAssignableFrom(clazz)) { //如果class实现类JSONSerializable接口,使用JSONSerializableSerializer序列化 put(clazz, writer = JSONSerializableSerializer.instance); } else if (JSONStreamAware.class.isAssignableFrom(clazz)) { //如果class实现类JSONStreamAware接口,使用MiscCodecr序列化 put(clazz, writer = MiscCodec.instance); } else if (clazz.isEnum()) { JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class); if (jsonType != null && jsonType.serializeEnumAsJavaBean()) { /** 如果是枚举类型,并且启用特性 serializeEnumAsJavaBean * 使用JavaBeanSerializer序列化(假设没有启用asm) */ put(clazz, writer = createJavaBeanSerializer(clazz)); } else { /** 如果是枚举类型,没有启用特性 serializeEnumAsJavaBean * 使用EnumSerializer序列化 */ put(clazz, writer = EnumSerializer.instance); } } else if ((superClass = clazz.getSuperclass()) != null && superClass.isEnum()) { JSONType jsonType = TypeUtils.getAnnotation(superClass, JSONType.class); if (jsonType != null && jsonType.serializeEnumAsJavaBean()) { /** 如果父类是枚举类型,并且启用特性 serializeEnumAsJavaBean * 使用JavaBeanSerializer序列化(假设没有启用asm) */ put(clazz, writer = createJavaBeanSerializer(clazz)); } else { /** 如果父类是枚举类型,没有启用特性 serializeEnumAsJavaBean * 使用EnumSerializer序列化 */ put(clazz, writer = EnumSerializer.instance); } } else if (clazz.isArray()) { Class
componentType = clazz.getComponentType(); ObjectSerializer compObjectSerializer = getObjectWriter(componentType); put(clazz, writer = new ArraySerializer(componentType, compObjectSerializer)); } else if (Throwable.class.isAssignableFrom(clazz)) { SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy); beanInfo.features |= SerializerFeature.WriteClassName.mask; put(clazz, writer = new JavaBeanSerializer(beanInfo)); } else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) { put(clazz, writer = MiscCodec.instance); } else if (Appendable.class.isAssignableFrom(clazz)) { put(clazz, writer = AppendableSerializer.instance); } else if (Charset.class.isAssignableFrom(clazz)) { put(clazz, writer = ToStringSerializer.instance); } else if (Enumeration.class.isAssignableFrom(clazz)) { put(clazz, writer = EnumerationSerializer.instance); } else if (Calendar.class.isAssignableFrom(clazz) // || XMLGregorianCalendar.class.isAssignableFrom(clazz)) { put(clazz, writer = CalendarCodec.instance); } else if (TypeUtils.isClob(clazz)) { put(clazz, writer = ClobSeriliazer.instance); } else if (TypeUtils.isPath(clazz)) { put(clazz, writer = ToStringSerializer.instance); } else if (Iterator.class.isAssignableFrom(clazz)) { put(clazz, writer = MiscCodec.instance); } else if (org.w3c.dom.Node.class.isAssignableFrom(clazz)) { put(clazz, writer = MiscCodec.instance); } else { if (className.startsWith("java.awt.") // && AwtCodec.support(clazz) // ) { // awt if (!awtError) { try { String[] names = new String[]{ "java.awt.Color", "java.awt.Font", "java.awt.Point", "java.awt.Rectangle" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = AwtCodec.instance); return writer; } } } catch (Throwable e) { awtError = true; // skip } } } // jdk8 if ((!jdk8Error) // && (className.startsWith("java.time.") // || className.startsWith("java.util.Optional") // || className.equals("java.util.concurrent.atomic.LongAdder") || className.equals("java.util.concurrent.atomic.DoubleAdder") )) { try { { String[] names = new String[]{ "java.time.LocalDateTime", "java.time.LocalDate", "java.time.LocalTime", "java.time.ZonedDateTime", "java.time.OffsetDateTime", "java.time.OffsetTime", "java.time.ZoneOffset", "java.time.ZoneRegion", "java.time.Period", "java.time.Duration", "java.time.Instant" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = Jdk8DateCodec.instance); return writer; } } } { String[] names = new String[]{ "java.util.Optional", "java.util.OptionalDouble", "java.util.OptionalInt", "java.util.OptionalLong" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = OptionalCodec.instance); return writer; } } } { String[] names = new String[]{ "java.util.concurrent.atomic.LongAdder", "java.util.concurrent.atomic.DoubleAdder" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = AdderSerializer.instance); return writer; } } } } catch (Throwable e) { // skip jdk8Error = true; } } if ((!oracleJdbcError) // && className.startsWith("oracle.sql.")) { try { String[] names = new String[] { "oracle.sql.DATE", "oracle.sql.TIMESTAMP" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = DateCodec.instance); return writer; } } } catch (Throwable e) { // skip oracleJdbcError = true; } } if ((!springfoxError) // && className.equals("springfox.documentation.spring.web.json.Json")) { try { put(Class.forName("springfox.documentation.spring.web.json.Json"), // writer = SwaggerJsonSerializer.instance); return writer; } catch (ClassNotFoundException e) { // skip springfoxError = true; } } if ((!guavaError) // && className.startsWith("com.google.common.collect.")) { try { String[] names = new String[] { "com.google.common.collect.HashMultimap", "com.google.common.collect.LinkedListMultimap", "com.google.common.collect.LinkedHashMultimap", "com.google.common.collect.ArrayListMultimap", "com.google.common.collect.TreeMultimap" }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = GuavaCodec.instance); return writer; } } } catch (ClassNotFoundException e) { // skip guavaError = true; } } if ((!jsonnullError) && className.equals("net.sf.json.JSONNull")) { try { put(Class.forName("net.sf.json.JSONNull"), writer = MiscCodec.instance); return writer; } catch (ClassNotFoundException e) { // skip jsonnullError = true; } } if (!jsonobjectError && className.equals("org.json.JSONObject")) { try { put(Class.forName("org.json.JSONObject"), writer = JSONObjectCodec.instance); return writer; } catch (ClassNotFoundException e) { // skip jsonobjectError = true; } } if ((!jodaError) && className.startsWith("org.joda.")) { try { String[] names = new String[] { "org.joda.time.LocalDate", "org.joda.time.LocalDateTime", "org.joda.time.LocalTime", "org.joda.time.Instant", "org.joda.time.DateTime", "org.joda.time.Period", "org.joda.time.Duration", "org.joda.time.DateTimeZone", "org.joda.time.UTCDateTimeZone", "org.joda.time.tz.CachedDateTimeZone", "org.joda.time.tz.FixedDateTimeZone", }; for (String name : names) { if (name.equals(className)) { put(Class.forName(name), writer = JodaCodec.instance); return writer; } } } catch (ClassNotFoundException e) { // skip jodaError = true; } } if ("java.nio.HeapByteBuffer".equals(className)) { put(clazz, writer = ByteBufferCodec.instance); return writer; } if ("org.javamoney.moneta.Money".equals(className)) { put(clazz, writer = MonetaCodec.instance); return writer; } Class[] interfaces = clazz.getInterfaces(); if (interfaces.length == 1 && interfaces[0].isAnnotation()) { put(clazz, AnnotationSerializer.instance); return AnnotationSerializer.instance; } if (TypeUtils.isProxy(clazz)) { //如果是CGLIB或javassist生成的代理类,就放父类的序列化器 Class
superClazz = clazz.getSuperclass(); ObjectSerializer superWriter = getObjectWriter(superClazz); put(clazz, superWriter); return superWriter; } //不管是不是动态代理类型,都是用JavaBean序列化器 if (Proxy.isProxyClass(clazz)) { Class handlerClass = null; if (interfaces.length == 2) { handlerClass = interfaces[1]; } else { for (Class proxiedInterface : interfaces) { if (proxiedInterface.getName().startsWith("org.springframework.aop.")) { continue; } if (handlerClass != null) { handlerClass = null; // multi-matched break; } handlerClass = proxiedInterface; } } if (handlerClass != null) { ObjectSerializer superWriter = getObjectWriter(handlerClass); put(clazz, superWriter); return superWriter; } } if (create) { writer = createJavaBeanSerializer(clazz); put(clazz, writer); } } if (writer == null) { //上面向config中添加了类对应的序列化器,现在获取Writer返回 writer = get(clazz); } } return writer; }

总结

整个解析过程,相对来说,比较地简单。因为,这个解析工作从原理上来讲,也并不复杂。困难地在于,如何处理不同的数据类型,以及在处理过程中如何保证处理的效率。这即是fastjson之所以产生的原因。
其它
具体的序列化各个函数
https://blog.csdn.net/weixin_41563161/article/details/105212421

2.3.8.2 反序列化过程

反序列化的含义是将跨语言的json字符串转换成java对象

思路

public static T parseObject(String text, Class clazz) {

/** 根据指定text,返回期望的java对象类型class */
return parseObject(text, clazz, new Feature[0]);
}

关键步骤

1创建解析配置ParserConfig对象,包括初始化内部反序列化实例和特性配置等。

2添加反序列化拦截器

3根据具体类型查找反序列化实例,执行反序列化转换

4解析对象内部引用

基本概念

词法分析是反序列化的重要基础,在其他框架druid、parsii等框架都用到了词法分析的技术,个人认为在讲反序列化之前讲词法分析更重要。

  • token-词法标记 用于标识当前在解析过程中解析到的对象的一个标记,具体的值参考 JSONToken。比如 {,即表示当前正在解析的是一个类似map或对象的格式,而},则表示当前对象已经到底了。
  • ch-当前字符 用于表示当前已经读取到的字符是什么,如 abc,当位置为1时,则当前字符为 b
  • bp-解析字符位置 用于表示当前字符所位于原始字符串中的哪一个位置,与ch是相对应的,它始终表示最新的一个位置,如果需要记录一些历史位置。如字符串起始位置,数字起始位置等,则需要使用其它标记,如np。
  • sbuf-字符缓冲 在解析字符串时的特殊存储区域,主要是用于解析转义字符时的临时存储区。即如果原字符串为 a\t,则实际解析的字符串应该为a\t,那么原字符串为3位长,解析之后为2位长。即需要另行存储。字符缓冲区如名所示,为一个字符数组,需要需要单独的定义来存储长度信息,如使用sp。
  • sp-字符缓冲区位置 这个用于表示在字符缓冲区之间记录当前字符串(或数字串)等的长度信息,同时也等同于当前的一个位置(如果坐标从0开始)。
  • np-数字解析位置 用于实际表示在解析到常量信息时起始点的标记位置。通过np + sp,即计算得出相应的区间值了。

解析规则

定义规则

  • 字符串 以"开头,并且以"结束,在中间可以存在以\为转义符,后面接"的情况,如 “”",认为是正确的。但 “”"",认为是错误的,其解析时在倒数第2个双引号时即结尾了。
  • 数字整形 以0-9开始,并且以连续数字,末尾可以s,b,f,d,l等
  • 数字小数 以0-9开始,默认为f,D或者,中间存在小数点
  • bool值 必须是 true 或 false ,全小写
  • 数组集合 以[ 开头,以]结尾,中间以任意,分隔的信息
  • set 以Set开头的,后面接数组集合的信息
  • treeSet 以TreeSet开头的,后面接数组集合的信息
  • 对象map 以{开始,以}结尾,中间按key,value集合的信息.
  • null值 必须为null
  • 字段 字符串,或单引号字符串,或无引号字符串,无引号时,必须为a-zA-Z_开头,以a-zA-Z0-9_结束.

词法规则

按照上面的定义,实际上就是贪婪的匹配规则,一旦满足一个匹配规则,那么这个匹配就要继续下去,直到当前规则不能完成时,同时在下一个规则之间,使用特定的分隔符作连接。
如 字符串 {a:“123”,b:[1,2,3]},即按以下规则进行
1.对象开始:{
2.对象key(即字段):a
3.分隔符: :
4.对象value开始:
5.字符串开始: "
6.字符串:123
7.字符串结束: "
8.对象value:结束:
9.对象间分隔符:,
10.对象key: b
11.分隔符: :
12.对象value开始:
13.数组开始: [
14.数组值1数字开始: 1
15.数组值1数字结束: 1,
16.数组分隔符: ,
17.…
18.数组结束: ]
19.对象结束: }

词法解析

整个词法,即TOKEN流,是由类JSONLexerBase来负责完成的,其负责提供主要词法单元的解析和结果取值操作。相应方法对应关系如下所示

  • 数字 scanNumber numberString intValue longValue floatValue doubleValue
  • 字符串 scanString stringVal
  • NULL值 scanNULL,scanNullOrNew
  • Boolean值 scanTrue,scanFalse

语法解析

1结束符判定
在词法解析上,fastjson根据第1个有效字符判定相应的类型,然后直到该类型结束之后,立即采用该类型。如以{开头,则一定返回object类型。对于类型 “{key:value} other” 这种非正确字符串,fastjson采用尾判断规则,即有效对象解析完毕之后,判定结束符必须已经到达字符串尾。如果Token值不是EOF,则表示字符串出现问题,而提示相错误的信息。
具体的判定,对应方法 DefaultJSONParser中的close()方法。

2忽略类型

默认情况下,fastjson对于json类型分别采用 set,treeSet,jsonArray,jsonObject,int(包含int,long,biginteger),float(包含float,double,bigDecimal),string,null,true,false来进行解析。即除基本的value词法表示外,其它均使用通用类型来表示。即数组使用set和jsonArray,对象使用jsonObject。

3数组解析

对应方法 Object parse(Object fieldName)

case LBRACKET:

JSONArray array = new JSONArray();
parseArray(array, fieldName);
return array;

如上所示,语法规则 [ 开始,表示为数组,则定义jsonArray,然后将此引用传递给具体的解析数组的方法中,以进行处理。jsonArray可以理解为使用ArrayList封装的复合对象。上面的fieldName解析对象时标识相应的key值,这里默认为null。以下代码忽略非关键性处理.

public final void parseArray(final Collection array, Object fieldName) {   .....    final JSONLexer lexer = getLexer();    //因为当前位置为[ 跳转到下一个词法单元处    lexer.nextToken(JSONToken.LITERAL_STRING);         for (int i = 0;; ++i) {   ......            Object value;            switch (lexer.token()) {                   case LITERAL_INT://当前值为int,解析value值,并跳转到下一个标记处                    value = lexer.integerValue();//如当前字符串为 1,2 则解析完1之后,跳转到,处,以方便后面作判断,并跳转至2处//这里的nextToken中的参数表示期望值,但实际上也不一定是该值,不过可以根据该值作一个进一步判定相应值。如这里期望,但也可以是一个 ],而表示解析结束                    lexer.nextToken(JSONToken.COMMA);                    break;                case LITERAL_FLOAT:......//解析小数                case LITERAL_STRING:......//解析字符串                    break;                case TRUE://解析true                case FALSE://解析false                case LBRACE://这里碰到一个{,表示数组中还内嵌有对象,则跳转到解析对象的地方                    JSONObject object = new JSONObject(isEnabled(Feature.OrderedField));                    value = parseObject(object, i);                    break;                case LBRACKET://这里碰到 [,则表示数组中还内嵌有数组,跳转到解析子数组的地方,这里的items值是新数组                    Collection items = new JSONArray();                    parseArray(items, i);                    value = items;                    break;                case NULL://解析null值                case UNDEFINED://js中的undefiend也认为是null值                case RBRACKET://这里碰到 ],则表示当前数组已经解析完毕,可以正常的return了。其它地方都是继续循环处理,即只有在这里才能正常跳出循环                    lexer.nextToken(JSONToken.COMMA);                    return;                case EOF://非正常跳出循环的地方,即字符串一下未匹配到] 就到末尾了                    throw new JSONException("unclosed jsonArray");                default://默认解析                    value = parse();                    break;            } //将上面解析到的对象添加到数组中            array.add(value); //这里因为前面在解析完之后,均往前解析了一位,即期望碰到 ,这里判断如果是 ,值 表示还有后续的value值//则继续往前解析,如 a,b 则期望当前位置从,处解析到b处            if (lexer.token() == JSONToken.COMMA) {                   lexer.nextToken(JSONToken.LITERAL_STRING);                continue;            }        }

类型处理

上面的为不带类型处理,则fastjson不知道应该将返回类型设置为什么类型。如果调用方主动的提示处理,则采用另一种处理方式,则根据提示类型对array以及object作处理。实际上,带类型处理的话,则会使用到ObjectDeserializer来进行解析。不过这里又会重新调用 DefaultJSONParser来进行处理。如对于(数组)或集合,则会使用 parseArray(Type type, Collection array, Object fieldName) 通过传递回来的collection对象,将相应值并根据type进行解析,再放回集合中。并根据返回类型进行调整。如数组,则会使用jsonArray进行二次转换来得到最终结果。代码参考如下:

public void parseArray(Type type, Collection array, Object fieldName) {   //这里根据type值获取具体类型的解析器        ObjectDeserializer deserializer = null;        if (int.class == type) {               deserializer = IntegerCodec.instance;            lexer.nextToken(JSONToken.LITERAL_INT);        }......             for (int i = 0;; ++i) {   ......                if (int.class == type) {                       Object val = IntegerCodec.instance.deserialze(this, null, null);                    array.add(val);                }...... //下一个元素解析                if (lexer.token() == JSONToken.COMMA) {                       lexer.nextToken(deserializer.getFastMatchToken());                    continue;                }            }

可以看出,此处解析与通用解析逻辑基本一致,惟一不同的即是这里使用了针对类型的各种deserializer解析器来完成针对类型的工作。

面向对象封装

在实际的使用场景,我们均会使用到如 parseObject(String text, Class clazz) 来期望返回具体的类型,这里实际上就会调用到了不同的类型反序列化器了。fastjson根据这里的类型,调用相应的序列化对象来完成不同的对象解析工作。

1类型映射

而序列化器的工作也并不是进行具体的语法解析,而是提供相应的类型信息,以期望jsonParser进行正常的解析工作。即具体的解析工作仍是由jsonParser来完成,ObjectDeserializer只不过提供一些上下文信息,以及对流程进行控制。

从 ObjectDeserializer的继承上可以看出,存在很多不同的反序列化器。同时,对于fastjson内置的反序列化器,采用了 ParserConfig.derializers来进行内部存储。因为默认情况下,会使用parseConfig的单例对象,因此这里的存储是全局共享的(实际上也没有关系)

2数字解析

对应类为IntegerCodec

public 
T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) { final JSONLexer lexer = parser.getLexer(); Integer intObj; if (lexer.token() == JSONToken.LITERAL_INT) { //如果token匹配到数字,而直接通过integer.parse强转 int val = lexer.intValue(); lexer.nextToken(JSONToken.COMMA); intObj = Integer.valueOf(val); } else if (lexer.token() == JSONToken.LITERAL_FLOAT) { //匹配到小数,而这里需要整数,而截取掉 BigDecimal decimalValue = lexer.decimalValue(); lexer.nextToken(JSONToken.COMMA); intObj = Integer.valueOf(decimalValue.intValue()); } else { //其它类型,采用类型转换强制转换,如匹配到字符串,也是可以转换为 整数的 Object value = parser.parse(); intObj = TypeUtils.castToInt(value); } //单独处理,使用IntegerCodec同时支持 int和 atomicInteger两种,算是偷懒吧 if (clazz == AtomicInteger.class) { return (T) new AtomicInteger(intObj.intValue()); } return (T) intObj; }

3数组(集合)解析

对应类CollectionDeserializer 数组对应为ArrayDeserializer

public 
T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { //根据类型获取不同的集合实现 Class
rawClass = getRawClass(type); //以下即根据不同的接口类 作不同的实现。因此在应用中,经常使用接口来标识不同的集合类 Collection list; if (rawClass == AbstractCollection.class) { //ArrayList } else if (rawClass.isAssignableFrom(HashSet.class)) { //HashSet } else if (rawClass.isAssignableFrom(LinkedHashSet.class)) { //LinkedHashSet } else if (rawClass.isAssignableFrom(TreeSet.class)) { //TreeSet } else if (rawClass.isAssignableFrom(ArrayList.class)) { //List } else if (rawClass.isAssignableFrom(EnumSet.class)) { //EnumSet } else { //默认情况下,直接实例化 list = (Collection) rawClass.newInstance(); } //这里尝试获取泛型实例信息,如 List
则获取string,即期望集合中每一项值均是 字符串 Type itemType; if (type instanceof ParameterizedType) { itemType = ((ParameterizedType) type).getActualTypeArguments()[0]; } else { itemType = Object.class; }//调用3.3中的不同类型解析公式处理 parser.parseArray(itemType, list, fieldName); return (T) list; }

4 javaBean封装解析

在实际解析过程中 javaBean与map的解析规则基本上一致。不过在map中的key值是任意的,而在javaBean中key值是固定的。即javaBean中可以控制在反序列化时哪些key是可接收的,哪些是不可接收的。

同时,javaBean通过配置项JsonField,可以重新配置字段的别名,从而映射到其它的key上。在map中, 均不存在相应的处理.

javaBean的过程可以理解为,先创建对象,然后每于{}中的每一项,先匹配key值,然后根据key值查找到相应的字段信息,根据不同的字段再解析该字段值。即语法表中的 pair: STRING ‘:’ value ;

具体的解析代码如下所示(忽略非关键信息)

public 
T deserialze(DefaultJSONParser parser, Type type, Object fieldName, Object object) { //简化判断,即针对原生json对象,使用类似map的解析规则 if (type == JSON.class || type == JSONObject.class) { return (T) parser.parse(); } //如果直接是一个null,则直接返回null即可,表示该对象不存在 if (lexer.token() == JSONToken.NULL) { lexer.nextToken(JSONToken.COMMA); return null; } Map
fieldValues = null; //预处理,如果直接为 {},则表示是空对象(不是null,直接返回 if (lexer.token() == JSONToken.RBRACE) { lexer.nextToken(JSONToken.COMMA); object = createInstance(parser, type); return (T) object; }...... for (;;) { //查找字段值 String key = lexer.scanSymbol(parser.getSymbolTable());......//这里因为找到了具体的字段,则根据字段进行解析该字段信息 boolean match = parseField(parser, key, object, type, fieldValues);//这里碰到了},表示对象已经解析结束,就不再处理了 if (lexer.token() == JSONToken.RBRACE) { lexer.nextToken(JSONToken.COMMA); break; } } return (T) object;

源码

public static T parseObject(String text, Class clazz) {

/** 根据指定text,返回期望的java对象类型class */
return parseObject(text, clazz, new Feature[0]);
}

这个反序列化接口可以处理对象包含任意字段类型,但是自身不能是泛型类型,原因是java的运行时类型擦除。fastjson给出了替代方法解决:

String json = “[{},…]”;

Type listType = new TypeReference<List>() {}.getType();
List modelList = JSON.parseObject(json, listType);

继续分析内部调用parseObject

public static T parseObject(String json, Class clazz, Feature… features) {
return (T) parseObject(json, (Type) clazz, ParserConfig.global, null, DEFAULT_PARSER_FEATURE, features);
}

//反序列化的过程

public static 
T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features) { if (input == null || input.isEmpty()) { return null; } /** 配置反序列化时启用的特性,比如是否允许json字符串字段不包含双引号 */ if (features != null) { for (Feature feature : features) { featureValues |= feature.mask; } } /** * 初始化DefaultJSONParser,反序列化类型由它 * 委托config查找具体序列化处理器处理 */ DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues); /** 添加拦截器 */ if (processor != null) { if (processor instanceof ExtraTypeProvider) { parser.getExtraTypeProviders().add((ExtraTypeProvider) processor); } if (processor instanceof ExtraProcessor) { parser.getExtraProcessors().add((ExtraProcessor) processor); } if (processor instanceof FieldTypeResolver) { parser.setFieldTypeResolver((FieldTypeResolver) processor); } } /** 使用反序列化实例转换对象,查找具体序列化实例委托给config查找 */ T value = (T) parser.parseObject(clazz, null); /** 处理json内部引用协议格式对象 */ parser.handleResovleTask(value); parser.close(); return (T) value; }

继续查看parser.parseObject(clazz, null)逻辑:

public 
T parseObject(Type type, Object fieldName) { int token = lexer.token(); /** 获取json串第一个有效token */ if (token == JSONToken.NULL) { /** 如果返回时null,自动预读下一个token */ lexer.nextToken(); return null; } /** 判定token属于字符串 */ if (token == JSONToken.LITERAL_STRING) { if (type == byte[].class) { /** 获取byte字节数据,分为十六进制和base64编码 */ byte[] bytes = lexer.bytesValue(); lexer.nextToken(); return (T) bytes; } /** 获取字符数组, 特殊处理String内存占用 */ if (type == char[].class) { String strVal = lexer.stringVal(); lexer.nextToken(); return (T) strVal.toCharArray(); } } ObjectDeserializer deserializer = config.getDeserializer(type); /** 委托config进行特定类型查找反序列化实例 */ try { if (deserializer.getClass() == JavaBeanDeserializer.class) { if (lexer.token()!= JSONToken.LBRACE && lexer.token()!=JSONToken.LBRACKET) { throw new JSONException("syntax error,except start with { or [,but actually start with "+ lexer.tokenName()); } /** 执行反序列化 */ return (T) ((JavaBeanDeserializer) deserializer).deserialze(this, type, fieldName, 0); } else { /** 执行反序列化 */ return (T) deserializer.deserialze(this, type, fieldName); } } catch (JSONException e) { throw e; } catch (Throwable e) { throw new JSONException(e.getMessage(), e); }}

反序列化核心逻辑还是在委托配置查找反序列化实例,我们具体看看是如何查找反序列化实例的, 进入ParserConfig#getDeserializer(java.lang.reflect.Type)自己查看逻辑:

//查找反序列化实例    public ObjectDeserializer getDeserializer(Type type) {           /** 首先从内部已经注册查找特定class的反序列化实例 */        ObjectDeserializer deserializer = get(type);        if (deserializer != null) {               /** 引用类型,根据特定类型再次匹配 */            return deserializer;        }        if (type instanceof Class
) { return getDeserializer((Class
) type, type); } if (type instanceof ParameterizedType) { /** 获取泛型类型原始类型 */ Type rawType = ((ParameterizedType) type).getRawType(); /** 泛型原始类型是引用类型,根据特定类型再次匹配 */ if (rawType instanceof Class
) { return getDeserializer((Class
) rawType, type); } else { /** 递归调用反序列化查找 */ return getDeserializer(rawType); } } if (type instanceof WildcardType) { /** 类型是通配符或者限定类型 */ WildcardType wildcardType = (WildcardType) type; Type[] upperBounds = wildcardType.getUpperBounds(); if (upperBounds.length == 1) { Type upperBoundType = upperBounds[0]; /** 获取泛型上界(? extends T),根据特定类型再次匹配 */ return getDeserializer(upperBoundType); } } /** 如果无法匹配到,使用默认JavaObjectDeserializer反序列化 */ return JavaObjectDeserializer.instance; }

反序列化匹配getDeserializer(Type)主要特定处理了泛型类型,取出泛型类型真实类型还是委托内部ParserConfig#getDeserializer(java.lang.Class<?>, java.lang.reflect.Type)进行精确类型查找:

public ObjectDeserializer getDeserializer(Class
clazz, Type type) { /** 首先从内部已经注册查找特定type的反序列化实例 */ ObjectDeserializer deserializer = get(type); if (deserializer != null) { return deserializer; } if (type == null) { type = clazz; } /** 再次从内部已经注册查找特定class的反序列化实例 */ deserializer = get(type); if (deserializer != null) { return deserializer; } { JSONType annotation = TypeUtils.getAnnotation(clazz,JSONType.class); if (annotation != null) { Class
mappingTo = annotation.mappingTo(); /** 根据类型注解指定的反序列化类型 */ if (mappingTo != Void.class) { return getDeserializer(mappingTo, mappingTo); } } } if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) { /** 根据泛型真实类型查找反序列化实例 */ deserializer = get(clazz); } if (deserializer != null) { return deserializer; } for (Module module : modules) { deserializer = module.createDeserializer(this, clazz); if (deserializer != null) { putDeserializer(type, deserializer); return deserializer; } } /** 获取class名称,进行类型匹配(可以支持高版本jdk和三方库) */ String className = clazz.getName(); className = className.replace('$', '.'); if (className.startsWith("java.awt.") // && AwtCodec.support(clazz)) { /** * 如果class的name是"java.awt."开头 并且 * 继承 Point、Rectangle、Font或者Color 其中之一 */ if (!awtError) { String[] names = new String[] { "java.awt.Point", "java.awt.Font", "java.awt.Rectangle", "java.awt.Color" }; try { for (String name : names) { if (name.equals(className)) { /** 如果系统支持4中类型, 使用AwtCodec 反序列化 */ putDeserializer(Class.forName(name), deserializer = AwtCodec.instance); return deserializer; } } } catch (Throwable e) { // skip awtError = true; } deserializer = AwtCodec.instance; } } if (!jdk8Error) { try { if (className.startsWith("java.time.")) { String[] names = new String[] { "java.time.LocalDateTime", "java.time.LocalDate", "java.time.LocalTime", "java.time.ZonedDateTime", "java.time.OffsetDateTime", "java.time.OffsetTime", "java.time.ZoneOffset", "java.time.ZoneRegion", "java.time.ZoneId", "java.time.Period", "java.time.Duration", "java.time.Instant" }; for (String name : names) { if (name.equals(className)) { /** 如果系统支持JDK8中日期类型, 使用Jdk8DateCodec 反序列化 */ putDeserializer(Class.forName(name), deserializer = Jdk8DateCodec.instance); return deserializer; } } } else if (className.startsWith("java.util.Optional")) { String[] names = new String[] { "java.util.Optional", "java.util.OptionalDouble", "java.util.OptionalInt", "java.util.OptionalLong" }; for (String name : names) { if (name.equals(className)) { /** 如果系统支持JDK8中可选类型, 使用OptionalCodec 反序列化 */ putDeserializer(Class.forName(name), deserializer = OptionalCodec.instance); return deserializer; } } } } catch (Throwable e) { // skip jdk8Error = true; } } if (!jodaError) { try { if (className.startsWith("org.joda.time.")) { String[] names = new String[] { "org.joda.time.DateTime", "org.joda.time.LocalDate", "org.joda.time.LocalDateTime", "org.joda.time.LocalTime", "org.joda.time.Instant", "org.joda.time.Period", "org.joda.time.Duration", "org.joda.time.DateTimeZone", "org.joda.time.format.DateTimeFormatter" }; for (String name : names) { if (name.equals(className)) { putDeserializer(Class.forName(name), deserializer = JodaCodec.instance); return deserializer; } } } } catch (Throwable e) { // skip jodaError = true; } } if ((!guavaError) // && className.startsWith("com.google.common.collect.")) { try { String[] names = new String[] { "com.google.common.collect.HashMultimap", "com.google.common.collect.LinkedListMultimap", "com.google.common.collect.LinkedHashMultimap", "com.google.common.collect.ArrayListMultimap", "com.google.common.collect.TreeMultimap" }; for (String name : names) { if (name.equals(className)) { putDeserializer(Class.forName(name), deserializer = GuavaCodec.instance); return deserializer; } } } catch (ClassNotFoundException e) { // skip guavaError = true; } } if (className.equals("java.nio.ByteBuffer")) { putDeserializer(clazz, deserializer = ByteBufferCodec.instance); } if (className.equals("java.nio.file.Path")) { putDeserializer(clazz, deserializer = MiscCodec.instance); } if (clazz == Map.Entry.class) { putDeserializer(clazz, deserializer = MiscCodec.instance); } if (className.equals("org.javamoney.moneta.Money")) { putDeserializer(clazz, deserializer = MonetaCodec.instance); } final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { /** 使用当前线程类加载器 查找 META-INF/services/AutowiredObjectDeserializer.class实现类 */ for (AutowiredObjectDeserializer autowired : ServiceLoader.load(AutowiredObjectDeserializer.class, classLoader)) { for (Type forType : autowired.getAutowiredFor()) { putDeserializer(forType, autowired); } } } catch (Exception ex) { // skip } if (deserializer == null) { deserializer = get(type); } if (deserializer != null) { return deserializer; } if (clazz.isEnum()) { if (jacksonCompatible) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if (TypeUtils.isJacksonCreator(method)) { deserializer = createJavaBeanDeserializer(clazz, type); putDeserializer(type, deserializer); return deserializer; } } } Class
deserClass = null; JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class); if (jsonType != null) { deserClass = jsonType.deserializer(); try { /** 如果是枚举类型并使用了注解,使用注解指定的反序列化 */ deserializer = (ObjectDeserializer) deserClass.newInstance(); putDeserializer(clazz, deserializer); return deserializer; } catch (Throwable error) { // skip } } /** 如果是枚举类型,使用EnumSerializer反序列化 */ deserializer = new EnumDeserializer(clazz); } else if (clazz.isArray()) { /** 如果是数组类型,使用数组对象反序列化实例 */ deserializer = ObjectArrayCodec.instance; } else if (clazz == Set.class || clazz == HashSet.class || clazz == Collection.class || clazz == List.class || clazz == ArrayList.class) { /** 如果class实现集合接口,使用CollectionCodec反序列化 */ deserializer = CollectionCodec.instance; } else if (Collection.class.isAssignableFrom(clazz)) { deserializer = CollectionCodec.instance; } else if (Map.class.isAssignableFrom(clazz)) { /** 如果class实现Map接口,使用MapDeserializer反序列化 */ deserializer = MapDeserializer.instance; } else if (Throwable.class.isAssignableFrom(clazz)) { /** 如果class继承Throwable类,使用ThrowableDeserializer反序列化 */ deserializer = new ThrowableDeserializer(this, clazz); } else if (PropertyProcessable.class.isAssignableFrom(clazz)) { deserializer = new PropertyProcessableDeserializer((Class
) clazz); } else if (clazz == InetAddress.class) { deserializer = MiscCodec.instance; } else { /** 默认使用JavaBeanDeserializer反序列化(没有开启asm情况下) */ deserializer = createJavaBeanDeserializer(clazz, type); } /** 加入cache,避免同类型反复创建 */ putDeserializer(type, deserializer); return deserializer;}

总结

其实查找反序列化和之前提到了序列化类似,根据特定类型匹配接口或者继承实现类查找的
其实在整个过程中,最核心的部分在于词法分析和语法解析.另外由于业务的复杂性以及在编码时的代码优化,fastjson在一些具体实现时,有一些额外的处理,导致逻辑上不是很懂。但是,理解了词法和语法,其它的看起来就不是太难了。
其它

  • JsonField 用于描述字段的序列信息及反序列信息,如重新设定name值,是否需要反序列化等.
  • JsonType 用于控制指定的类进行反序列化时的信息,如使用其它类作为映射信息.
  • JsonCreator 用于控制在反序列化时初始化object时,采用哪一个构造函数或者工厂方法
  • ExtraTypeProvider 用于控制在javaBean序列化时,字段的类型信息重新设定。比如 字段类型为Object,可以通过这个接口重新设定它的具体类型.
  • ExtraProcessor 用于控制在序列化及反序列化时,如果碰到不同的解析的字段时,可以通过此接口重新 进行处理。如 字段a,在{“b”:“abc”},可以通过这个接口重新将字段b所对应的值映射到字段a上。
  • ObjectDeserializer 最后可以自已定义反序列化器,通过ParseConfig.putDeserializer 来添加相应的反序列化器

2.3.9 springboot集成FastJSON

1.引jar

com.alibaba
fastjson
1.2.47

2.3.10 Fastjson中的优化

2.3.10.1 Fastjson中Serialzie的优化实现

1、自行编写类似StringBuilder的工具类SerializeWriter。

把java对象序列化成json文本,是不可能使用字符串直接拼接的,因为这样性能很差。比字符串拼接更好的办法是使用java.lang.StringBuilder。StringBuilder虽然速度很好了,但还能够进一步提升性能的,fastjson中提供了一个类似StringBuilder的类com.alibaba.fastjson.serializer.SerializeWriter。

SerializeWriter提供一些针对性的方法减少数组越界检查。例如public void writeIntAndChar(int i, char c) {},这样的方法一次性把两个值写到buf中去,能够减少一次越界检查。目前SerializeWriter还有一些关键的方法能够减少越界检查的,我还没实现。也就是说,如果实现了,能够进一步提升serialize的性能。

2、使用ThreadLocal来缓存buf。

这个办法能够减少对象分配和gc,从而提升性能。SerializeWriter中包含了一个char[] buf,每序列化一次,都要做一次分配,使用ThreadLocal优化,能够提升性能。

3、使用asm避免反射

获取java bean的属性值,需要调用反射,fastjson引入了asm的来避免反射导致的开销。fastjson内置的asm是基于objectweb asm 3.3.1改造的,只保留必要的部分,fastjson asm部分不到1000行代码,引入了asm的同时不导致大小变大太多。

4、使用一个特殊的IdentityHashMap优化性能。

fastjson对每种类型使用一种serializer,于是就存在class -> JavaBeanSerizlier的映射。fastjson使用IdentityHashMap而不是HashMap,避免equals操作。我们知道HashMap的算法的transfer操作,并发时可能导致死循环,但是ConcurrentHashMap比HashMap系列会慢,因为其使用volatile和lock。fastjson自己实现了一个特别的IdentityHashMap,去掉transfer操作的IdentityHashMap,能够在并发时工作,但是不会导致死循环。

5、缺省启用sort field输出

json的object是一种key/value结构,正常的hashmap是无序的,fastjson缺省是排序输出的,这是为deserialize优化做准备。

6、集成jdk实现的一些优化算法

在优化fastjson的过程中,参考了jdk内部实现的算法,比如int to char[]算法等等。

2.3.10.2 Fastjson中deserializer的主要优化实现

deserializer也称为parser或者decoder,fastjson在这方面投入的优化精力最多。

1、读取token基于预测。
所有的parser基本上都需要做词法处理,json也不例外。fastjson词法处理的时候,使用了基于预测的优化算法。比如key之后,最大的可能是冒号":",value之后,可能是有两个,逗号",“或者右括号”}"。在com.alibaba.fastjson.parser.JSONScanner中提供了这样的方法:
Java代码

从上面摘抄下来的代码看,基于预测能够做更少的处理就能够读取到token。

2、sort field fast match算法
fastjson的serialize是按照key的顺序进行的,于是fastjson做deserializer时候,采用一种优化算法,就是假设key/value的内容是有序的,读取的时候只需要做key的匹配,而不需要把key从输入中读取出来。通过这个优化,使得fastjson在处理json文本的时候,少读取超过50%的token,这个是一个十分关键的优化算法。基于这个算法,使用asm实现,性能提升十分明显,超过300%的性能提升。
{ “id” : 123, “name” : “魏加流”, “salary” : 56789.79}


在上面例子看,虚线标注的三个部分是key,如果key_id、key_name、key_salary这三个key是顺序的,就可以做优化处理,这三个key不需要被读取出来,只需要比较就可以了。

这种算法分两种模式,一种是快速模式,一种是常规模式。快速模式是假定key是顺序的,能快速处理,如果发现不能够快速处理,则退回常规模式。保证性能的同时,不会影响功能。

在这个例子中,常规模式需要处理13个token,快速模式只需要处理6个token。

实现sort field fast match算法的代码在这个类[com.alibaba.fastjson.parser.deserializer.ASMDeserializerFactory|http://code.alibabatech.com/svn/fastjson/trunk/fastjson/src/main/java/com/alibaba/fastjson/parser/deserializer/ASMDeserializerFactory.java],是使用asm针对每种类型的VO动态创建一个类实现的。

这里是有一个用于演示sort field fast match算法的代码:
http://code.alibabatech.com/svn/fastjson/trunk/fastjson/src/test/java/data/media/ImageDeserializer.java

// 用于快速匹配的每个字段的前缀

char[] size_   = "\"size\":".toCharArray();  char[] uri_    = "\"uri\":".toCharArray();  char[] titile_ = "\"title\":".toCharArray();  char[] width_  = "\"width\":".toCharArray();  char[] height_ = "\"height\":".toCharArray();    // 保存parse开始时的lexer状态信息  int mark = lexer.getBufferPosition();  char mark_ch = lexer.getCurrent();  int mark_token = lexer.token();    int height = lexer.scanFieldInt(height_);  if (lexer.matchStat == JSONScanner.NOT_MATCH) {       // 退出快速模式, 进入常规模式     lexer.reset(mark, mark_ch, mark_token);    return (T) super.deserialze(parser, clazz);  }    String value = lexer.scanFieldString(size_);  if (lexer.matchStat == JSONScanner.NOT_MATCH) {         // 退出快速模式, 进入常规模式      lexer.reset(mark, mark_ch, mark_token);      return (T) super.deserialze(parser, clazz);  }  Size size = Size.valueOf(value);    // ... ...    // batch set  Image image = new Image();  image.setSize(size);  image.setUri(uri);  image.setTitle(title);  image.setWidth(width);  image.setHeight(height);    return (T) image;

3、使用asm避免反射

deserialize的时候,会使用asm来构造对象,并且做batch set,也就是说合并连续调用多个setter方法,而不是分散调用,这个能够提升性能。

4、对utf-8的json bytes,针对性使用优化的版本来转换编码。

这个类是com.alibaba.fastjson.util.UTF8Decoder,来源于JDK中的UTF8Decoder,但是它使用ThreadLocal Cache Buffer,避免转换时分配char[]的开销。
ThreadLocal Cache的实现是这个类com.alibaba.fastjson.util.ThreadLocalCache。第一次1k,如果不够,会增长,最多增长到128k。

Java代码

6、symbolTable算法

我们看xml或者javac的parser实现,经常会看到有一个这样的东西symbol table,它就是把一些经常使用的关键字缓存起来,在遍历char[]的时候,同时把hash计算好,通过这个hash值在hashtable中来获取缓存好的symbol,避免创建新的字符串对象。这种优化在fastjson里面用在key的读取,以及enum value的读取。这是也是parse性能优化的关键算法之一。

以下是摘抄自JSONScanner类中的代码,这段代码用于读取类型为enum的value。

Java代码

int hash = 0;  for (;;) {         ch = buf[index++];      if (ch == '\"') {             bp = index;          this.ch = ch = buf[bp];          strVal = symbolTable.addSymbol(buf, start, index - start - 1, hash); // 通过symbolTable来获得缓存好的symbol,包括fieldName、enumValue          break;      }            hash = 31 * hash + ch; // 在token scan的过程中计算好hash        // ... ...  }

2.3.11 简易版的Fastjson

public static void main(String[] args) throws IllegalAccessException {           // 创建需要转换的对象        Person person = new Person();        person.setName("小明");        person.setAge(17);        person.setSex("男");        // 将对象转换为Json字符串        String jsonString = MyJson.toJsonString(person);        // 打印到控制台        System.out.println(jsonString);    }    public static final String toJsonString(Object object) throws IllegalAccessException {           // 获取反射对象        Class
clazz = object.getClass(); // 获取反射对象的所有属性,包括私有属性 Field[] fields = clazz.getDeclaredFields(); // 创建字符串类,便于拼接出JSON字符串 StringBuffer stringBuffer = new StringBuffer(); String str = ""; stringBuffer.append("{"); // 遍历所有属性 for (Field field : fields) { // 第一次无须拼接逗号 if (stringBuffer.length() != 1) { stringBuffer.append(","); }// 给私有属性授权,以便能够对于私有属性操作 field.setAccessible(true); stringBuffer.append("\""); stringBuffer.append(field.getName()); stringBuffer.append("\""); stringBuffer.append(":"); // 两种判断属性值是否为字符串类型的方式 Boolean flag = field.getType().isInstance(str);// Boolean flag = field.getType().toString().equals("class java.lang.String"); if (flag) { // 如果属性的类型为字符串,则给属性值加上双引号 stringBuffer.append("\""); stringBuffer.append(field.get(object)); stringBuffer.append("\""); } else { stringBuffer.append(field.get(object)); } } stringBuffer.append("}"); return stringBuffer.toString();}

在这里插入图片描述

虽然造轮子的过程可能比较复杂,但我只需要编写一次,之后无论是什么对象我就可以直接使用。

3.参考文献

https://zhuanlan.zhihu.com/p/62763428

https://www.iflym.com/index.php/code/alibaba-fastjson-json-serializer-chapter-source-analyse-one-global-analyse.html

4.总结

学习手稿

在学习过程中如果觉得电脑不足以让你有清楚的思路,那么可以把它写下来,这样会有意想不到的收获。

在这里插入图片描述

在这里插入图片描述

公众号

博客地址

https://blog.csdn.net/weixin_41563161
掘金https://juejin.cn/user/2814360172369271

知乎https://www.zhihu.com/people/hai-kuo-tian-kong-63-38-21

在这里插入图片描述

你可能感兴趣的文章
mysqli
查看>>
MySQLIntegrityConstraintViolationException异常处理
查看>>
mysqlreport分析工具详解
查看>>
MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
查看>>
Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
查看>>
mysql_real_connect 参数注意
查看>>
mysql_secure_installation初始化数据库报Access denied
查看>>
MySQL_西安11月销售昨日未上架的产品_20161212
查看>>
Mysql——深入浅出InnoDB底层原理
查看>>
MySQL“被动”性能优化汇总
查看>>
MySQL、HBase 和 Elasticsearch:特点与区别详解
查看>>
MySQL、Redis高频面试题汇总
查看>>
MYSQL、SQL Server、Oracle数据库排序空值null问题及其解决办法
查看>>
mysql一个字段为空时使用另一个字段排序
查看>>
MySQL一个表A中多个字段关联了表B的ID,如何关联查询?
查看>>
MYSQL一直显示正在启动
查看>>
MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
查看>>
MySQL万字总结!超详细!
查看>>
Mysql下载以及安装(新手入门,超详细)
查看>>
MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
查看>>