fastJSON源码分析_3_浅析对象序列化器的实现

2021SC@SDUSC

 本篇简介

上一篇文章中我们知道了fastJSON是如何通过JSONSerializeConfig这个类来选择我们所需要序列化的对象的序列化器.而本篇文章的内容就是对ObjectSerializer接口具体实现了的类进行分析,了解在序列化的过程中,它是如何将我们的对象转化为JSON字符串的.

源码分析

上一篇文章中,我们看到了SerializeConfig维护了两种map,其中的一种map是用来保存class和序列化器的对应关系的,而在初始化的时候,我们看到了如下代码,也就是说初始化时往map中添加了基本数据类型的包装类的序列化器.而这些序列化器都来自于后缀为codec的类的实例.

xxCodec

这时可能会有疑惑,按照命名规则,这个ObjectSerializer的实现类为什么是一个名字叫codec的类?

让我们来看看IntegerCodec的具体内容吧!

 首先,我们看到这个Codec不仅实现了ObjectSerializer,还实现了ObjectDeserializer,所以说它并非是单纯的序列化器,而是还有反序列化器的功能,于是被命名为编码器.

这里我们只关注序列化器的内容,所以再看下一行代码,也就是map中所调用的instance,这是Integer类的一个静态实例,在map初始化的时候,调用该变量将会使jvm加载IntegerCodec类从而实现静态对象的创建.而再往下就是该编码器的序列化功能的核心代码,实现于ObjectSerializer的write方法.

并且在第一行我们看到了,这方法中调用了上层的JSONSerializer所维护的SerializeWriter这个输出器,用来实现输出的功能.

 紧接着后面就是根据数据的类型,数值,以及相应的配置来使输出器输出相应的内容.例如

1.value==null

 

输出null

2.使用feature,writeClassName

 输出10B.

这里有意思的是,明明是对Integer类进行序列化,但是却要判断该类是否是Long的实例,并且在map中还有单独的LongCodec来处理Long类的序列化 .

 我的猜测是,可能这里是用来来判断是否有转型情况.

还有一点需要解释的是关于SerializerFeature的结构,这个类是一个枚举类,其中定义了许多的枚举项,通过判断输出器是否开启了相应的项目,来实现对数据不同的处理(具体该类的实现我在后面补充).

通过上述对Codec的分析我们可以了解到这些编码器的大致结构了,也就是使用write方法,对序列化对象进行分析然后根据配置情况,调用输出器来实现相应的功能.

JavaBeanSerializer简析

 实际上,除了Codec这样的编码器,还有专门的序列化器,这里我们就以使用最普遍的序列化器,JavaBeanSerializer来作一个简单分析.

在我们使用fastJSON的过程中,会编写自己的类并使用其对象,而在对这种对象进行序列化的时候,就会使用JavaBeanSerializer这样的序列化器进行序列化操作,为什么是JavaBean呢,在fastJSON使用范例中我们知道,普通的java对象是无法进行序列化的,只有满足JavaBean规范的类才可以被正确地序列化输出.因为Bean满足规范,所以能够方便的通过规范来进行访问.

我们自己写的JavaBean不像Integer这些已经在库的类,每一个类都有编写完的编码器,JavaBean中存在我们自己定义的变量,这些变量可以是基本数据类型,可以是对象,也可以是两者的数组等数据结构.所以说,JavaBeanserializer的实现一定是需要通过输入的bean的信息来创建的.

关于JavaBeanSerializer的创建

 我们可以看到,在SerializeConfig的getObjectWriter中,有一个叫create的参数,并且在writeJSONString方法里会调用到getobjectWriter(clazz)的方法,而这个方法会去调用create默认为true的该方法.

当该方法在一步步判断我们的需序列化对象有没有序列化器后,最终会因为这是一个bean对象而跳到这个方法的末尾:

这几行代码的意思很简单,就是create为true,我们就自己创建一个并添加到map中,然后去取出来返回.重点就在这个createJavaBeanSerializer上面,我们继续跟进到方法中:

 TypeUtils是fastJSON的工具类,它的功能包括类型转化,类的信息获取等等(得以后再说),前面几行代码在查找我们的类是否支持,这里用了FNV-1a的哈希算法来获取唯一id,并且用二分搜索法和denyclasses中的内容进行匹配(事实上这个数组只有两个元素).

然后再通过TypeUtils获取bean的信息,再看这个类是否是遍历器,当然最重要的是返回了一个用beaninfo作参数的重载方法.再继续跟进后就会发现代码变得复杂了起来,因为要开始使用ASM的技术了:

 ASM是什么呢,简要说明,这里的ASM就是用来代替JAVA反射机制的一种技术,因为我们现在相当于需要动态创建一个新的序列化器,里面所有的变量是来自于我们自己写的bean的内容,按照原来的方法这就需要使用java反射机制来动态生成类,但是ASM提供了字节码级别的修改技术,能够更加快速地生成类(其实不止于这个功能),所以这里就使用了该技术.但是使用该技术需要符合一定条件,

而这个方法的大部分if语句其实都是在判断是否符合使用asm的条件,比如

if (jsonType.asm() == false) {
    asm = false;
}

这段代码指的是在jsonType注解配置中是否关闭了asm,即:

@JSONType(asm = false)

还有各种各样的情况,作一个总结:

  • 如果在安卓上使用fastJSON默认为关
  • 配置的了特定的feature,关闭asm
  • 配置了SerializeFilter,关闭asm
  • 如果类的修饰符不是public,关闭asm
  • 如果类名包含某些字符,关闭asm
  • 如果是接口类,关闭asm
  • 检查类的类型,注解,返回值,不符合的关闭asm

最后如果asm开启,则会使用工厂AsmSerializerFactory来创建JavaBeanSerializer,否则是直接通过JavaBeanSerializer的构造函数来创建.

JavaBeanSerializer类

和Codec相似,但是这个类在创建时,通过beanInfo获取到了所有的field信息,然后保存为数组getters,方便到时候的取出来使用.所以说,这个类虽然很长(后面再来详细解释),但是功能就同StringBuilder一样,通过数据与配置来决定如何构建JSON字符串,最终仍然通过输出器来达到javaBean序列化的目的.

总结

通过对源码的简要分析,我们搞清楚了基本序列化器(编码器)与bean序列化器的大致结构,并且本篇文章还简要说明了ASM技术的作用.在分析的过程中,我渐渐发现在正式的项目中,有着许许多多的设计模式,比如ASM序列化器工厂模式,这些设计模式的运用让提升了代码的运行效率,值得我们在之后的编程和设计中尝试着使用.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值