2021SC@SDUSC
简介
本篇是fastjson源码分析的最后一篇,本篇的主要内容是对之前分析过程中的流程做个总结,并总结在之前fastjson中分析到的设计模式;
类间关系
下面以类图的形式给出类间关系的总览:
图中的JSON抽象类是入口类,它提供了大量的静态方法;JSONObject类用于存储返回对象,继承自JSON抽象类;DefaultJSONParser类是解析器,它依赖于JSONObject类、JSONLexer接口、JSONLexerBase抽象类、ObjectDeserializer接口、ParserConfig类,并组合到JSON类上;ObjectDeserializer接口提供了泛型的支持,它通过xxxDeserializer类的具体实现返回特定类型xxx的对象;ParserConfig类进行配置信息的配置和处理,它被分离出来是因为对泛型的支持使得解析器的配置信息变得太过复杂;JSONSCanner类和JSONReaderScanner类实现了JSONLexerBase抽象类,该流程中真正被使用的是JSONScanner类,它组合到DefaultJSONParser类上;JSONException类表达了异常信息,且被大量的类所依赖,因此单独画出。
类间的关系很好的符合了面向对象的基本原则如JSONLexer接口和JSONLexerBase抽象类的引入也使得能够更好地扩展词法分析器,这符合开闭原则。当一个类要使用另一个类时,都尽量使用了关联(更确切的说是组合)的关系,这符合了复用原则等;
序列化的流程
为了说明fastjson的序列化方法,下述简单的画出了时序图以说明序列化的流程:
设计模式的分析
下面举例几个在之前的分析中遇到的设计模式:
单例模式
含义:一个类仅有一个实例并提供一个全局的访问点
考虑到Fastjson对快速处理的需求,当大量的序列化/反序列化请求同时到达时,对某些对象(如Deserializer)频繁的创建和销毁会带来不小的开销,我们猜测为了减小这部分不必要的开销,Fastjson很可能使用了单例模式。
如我们上节分析到的mapSerializer,就采用了单例模式:
public class MapDeserializer implements ObjectDeserializer {
public static MapDeserializer instance = new MapDeserializer();
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
...
}
...
}
它实现了ObjectDeserializer接口,重写了deserialze方法(此处Fastjson中存在拼写错误)以完成对JSON字符串表示的Map对象的反序列化。它在类加载时进行初始化,是典型的饿汉式的单例模式实现。其应用场景也十分鲜明,是为了节省反复创建和销毁的系统开销。
外部对MapDeserializer类的访问是如下进行的:
public <T> T parseObject(Type type, Object fieldName) {
...
ObjectDeserializer derializer = config.getDeserializer(type);
...
return (T) derializer.deserialze(this, type, fieldName);
}
当调用者调用了支持泛型的parseObject函数时,它通过ParserConfig类的实例config取得MapDeserializer类的实例,然后调用其deserialze方法进行对应类型的反序列化,最终返回对应类型的对象。而config.getDeserializer是这样实现的:
public ObjectDeserializer getDeserializer(Type type) {
ObjectDeserializer derializer = this.deserializers.get(type);
...
}
其中this.deserializers是ParserConfig类中的成员变量:
private final IdentityHashMap<Type, ObjectDeserializer> deserializers =
new IdentityHashMap<Type, ObjectDeserializer>();
它是一个哈希表,通过get方法可以使用Type得到对应的反序列化器,它在该类的对象被创建时初始化。
代理模式
含义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
当我们调用parseObject方法将JSON字符串反序列化成一个接口类的对象时,由于接口类没有get和set方法的具体实现,我们无法get和set类中的值。另一方面,一个接口类无法实例化出对象。因此Fastjson实际上通过动态代理创建并返回了一个代理对象,具体如下:
public Object createInstance(DefaultJSONParser parser, Type type) {
if (type instanceof Class) {
if (clazz.isInterface()) {
Class<?> clazz = (Class<?>) type;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
final JSONObject obj = new JSONObject();
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { clazz },
obj);
return proxy;
}
}
...
}
当反序列化的目标是一个接口类时,实际上一个JSONObject对象被创建以存储键值对,然后通过动态代理,调用newProxyInstance创建并返回了一个代理对象。在JSONObject类中重写了invoke方法,使得其可以拦截get和set方法,以解决接口类无法get和set的问题。总而言之,通过代理对象+JSONObject对象来实现反序列化接口类对象,其实是一种虚拟化。而通过代理对象来完成对JSONObject对象的访问则是使用了代理模式。
策略模式
含义: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
我们回顾之前的uml类图:
实际上还有很多其他的类也实现了ObjectDeserializer接口,ObjectDeserializer接口类中只有两个方法:
public interface ObjectDeserializer {
<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
int getFastMatchToken();
}
它的子类重写了这两个方法,这是策略模式典型的应用场景。通过策略模式使得架构清晰且符合开闭原则,我们可以很容易增加新的特定类型反序列化器。
结语
感谢您对之前fastjson源码分析的阅读,本人水平有限很多分析并不是十分到位,对其中的设计模式等的分析也只是泛泛而谈并无非常深入,一学期的课程即将结束,助读者元旦快乐新年大吉!!!