fastjson源码解析——反序列化特辑(一)

2021SC@SDUSC

本文在CSDN个人博客同步发出,地址CSDN博客

概要

上篇fastjson源码解析——反序列化(三)详细介绍了fastjson如何创建无反序列化实例类的反序列化实例,介绍了如何通过java.lang.reflect查询到所有的Getter/Setter方法。


本期是一个特辑,专门介绍反序列化接口实现方法中,对已知类型类的反序列化实例的内部注册。

正式开始

在上期中,我提到了 对不同的Getter/Setter做处理,并且保存信息返回反序列化的上层函数。
承接上期,我详细介绍对不同类型类反序列化实例的内部注册
若所涉及的类型为:

已注册的类型

fastjson在内部已经注册了常用类型的反序列化实现方案,根据源代码注册的函数initDeserialize()代码如下:

这部分代码可以完全不看,直接看我下面整理的表格即可看到清晰的对应关系(由代码一一查找)

private void initDeserializers() {
        deserializers.put(SimpleDateFormat.class, MiscCodec.instance);
        deserializers.put(Calendar.class, CalendarCodec.instance);
        deserializers.put(XMLGregorianCalendar.class, CalendarCodec.instance);

        deserializers.put(JSONObject.class, MapDeserializer.instance);
        deserializers.put(JSONArray.class, CollectionCodec.instance);

        deserializers.put(Map.class, MapDeserializer.instance);
        deserializers.put(HashMap.class, MapDeserializer.instance);
        deserializers.put(LinkedHashMap.class, MapDeserializer.instance);
        deserializers.put(TreeMap.class, MapDeserializer.instance);
        deserializers.put(ConcurrentMap.class, MapDeserializer.instance);
        deserializers.put(ConcurrentHashMap.class, MapDeserializer.instance);

        deserializers.put(Collection.class, CollectionCodec.instance);
        deserializers.put(List.class, CollectionCodec.instance);
        deserializers.put(ArrayList.class, CollectionCodec.instance);

        deserializers.put(Object.class, JavaObjectDeserializer.instance);
        deserializers.put(String.class, StringCodec.instance);
        deserializers.put(StringBuffer.class, StringCodec.instance);
        deserializers.put(StringBuilder.class, StringCodec.instance);
        deserializers.put(char.class, CharacterCodec.instance);
        deserializers.put(Character.class, CharacterCodec.instance);
        deserializers.put(byte.class, NumberDeserializer.instance);
        deserializers.put(Byte.class, NumberDeserializer.instance);
        deserializers.put(short.class, NumberDeserializer.instance);
        deserializers.put(Short.class, NumberDeserializer.instance);
        deserializers.put(int.class, IntegerCodec.instance);
        deserializers.put(Integer.class, IntegerCodec.instance);
        deserializers.put(long.class, LongCodec.instance);
        deserializers.put(Long.class, LongCodec.instance);
        deserializers.put(BigInteger.class, BigIntegerCodec.instance);
        deserializers.put(BigDecimal.class, BigDecimalCodec.instance);
        deserializers.put(float.class, FloatCodec.instance);
        deserializers.put(Float.class, FloatCodec.instance);
        deserializers.put(double.class, NumberDeserializer.instance);
        deserializers.put(Double.class, NumberDeserializer.instance);
        deserializers.put(boolean.class, BooleanCodec.instance);
        deserializers.put(Boolean.class, BooleanCodec.instance);
        deserializers.put(Class.class, MiscCodec.instance);
        deserializers.put(char[].class, new CharArrayCodec());

        deserializers.put(AtomicBoolean.class, BooleanCodec.instance);
        deserializers.put(AtomicInteger.class, IntegerCodec.instance);
        deserializers.put(AtomicLong.class, LongCodec.instance);
        deserializers.put(AtomicReference.class, ReferenceCodec.instance);

        deserializers.put(WeakReference.class, ReferenceCodec.instance);
        deserializers.put(SoftReference.class, ReferenceCodec.instance);

        deserializers.put(UUID.class, MiscCodec.instance);
        deserializers.put(TimeZone.class, MiscCodec.instance);
        deserializers.put(Locale.class, MiscCodec.instance);
        deserializers.put(Currency.class, MiscCodec.instance);

        deserializers.put(Inet4Address.class, MiscCodec.instance);
        deserializers.put(Inet6Address.class, MiscCodec.instance);
        deserializers.put(InetSocketAddress.class, MiscCodec.instance);
        deserializers.put(File.class, MiscCodec.instance);
        deserializers.put(URI.class, MiscCodec.instance);
        deserializers.put(URL.class, MiscCodec.instance);
        deserializers.put(Pattern.class, MiscCodec.instance);
        deserializers.put(Charset.class, MiscCodec.instance);
        deserializers.put(JSONPath.class, MiscCodec.instance);
        deserializers.put(Number.class, NumberDeserializer.instance);
        deserializers.put(AtomicIntegerArray.class, AtomicCodec.instance);
        deserializers.put(AtomicLongArray.class, AtomicCodec.instance);
        deserializers.put(StackTraceElement.class, StackTraceElementDeserializer.instance);

        deserializers.put(Serializable.class, JavaObjectDeserializer.instance);
        deserializers.put(Cloneable.class, JavaObjectDeserializer.instance);
        deserializers.put(Comparable.class, JavaObjectDeserializer.instance);
        deserializers.put(Closeable.class, JavaObjectDeserializer.instance);

        deserializers.put(JSONPObject.class, new JSONPDeserializer());
        ModuleUtil.callWhenHasJavaSql(initDeserializersWithJavaSql);
    }

以下是我根据上述代码整理的对应表格

注册的类型 反序列化实例 是否支持序列化 是否支持反序列化
SimpleDateFormat MiscCodec
Calendar CalendarCodec
XMLGregorianCalendar CalendarCodec
JSONObject MapDeserializer -
JSONArray CollectionCodec
**Map MapDeserializer -
Collection CollectionCodec
List CollectionCodec
ArrayList CollectionCodec
Object JavaObjectDeserializer -
String StringCodec
StringBuffer StringCodec
StringBuilder StringCodec
char/Character CharacterCodec
byte/Byte NumberDeserializer -
short/Short NumberDeserializer -
int/Integer IntegerCodec
long/Long LongCodec
BigInteger BigIntegerCodec
BigDecimal BigDecimalCodec
float/Float FloatCodec
double/Double NumberDeserializer -
boolean/Boolean BooleanCodec
Class MiscCodec
char[] CharArrayCodec -
Atomic* *Codec 随*的属性
WeakReference ReferenceCodec
SoftReference ReferenceCodec
UUID/TimeZone/Locale/Currency MiscCodec
Inet4/6/SocketAddress MiscCodec
File/URI/URL MiscCodec
Pattern/Charset/JSONPath MiscCodec
Serializable JavaObjectDeserializer -
Cloneable JavaObjectDeserializer -
Comparable JavaObjectDeserializer -
Closeable JavaObjectDeserializer -
JSONPObject JSONPDeserializer -

通过先在内部注册不同类型的序列化/反序列化实例,可以让fastjson在运行时能够查找到特定的反序列化实例而不需要使用默认Java的反序列化实例。

从我整理的这张表,能看出3个问题:

  1. 几乎所有的类型都有已经存在的反序列化实例

  2. fastjson放弃部分类的序列化实现,但是仍然保留了这些类的反序列化操作

    个人推测,fastjson没有实现序列化的这部分类太过于复杂,内部字段过多,或者这些类没有遵守JavaBean的标准,其内部并没有Getter/Setter方法

  3. 通过查看反序列化实例中,包含Codec字段的类,可发现这些类都是对应类型的序列化实例。fastjson中序列化实例都同时实现了反序列化的操作,且内部注册的类型极多。若发送方使用fastjson序列化生成JSONString,接收方调用反序列化操作时,可以保证“谁序列化,谁也执行反序列化操作”

    这一特点,在保证稳定性的同时,大大降低了程序间的耦合性,极大减少了程序员维护代码的成本代价。若后续发现某类型的反序列化实例出现bug,可以针对性地对某个实例debug,不需要牵涉到其他任何实例。

总而言之,这样的程序设计逻辑,保证了fastjson极高的性能,较低的程序后期维护成本。

上一期我们见识到了如何规范代码,提高代码可读性。这一期,我们又可以窥探到阿里巴巴开发者对程序耦合性细致入微的把握。通过遍历、细分所有Java常见类,先行注册反序列化实例,提高性能,又因为仔细分类,使用序列化实例完成反序列化操作,降低耦合度,提高稳定性。

我自己认为,我还写不出具有这样性能与稳定性同时提高的优化逻辑的代码。这说明以后我们该学习的还有很多,还需要慢慢提高自己

最后

fastjson反序列化的部分暂时介绍到这里。特辑一详细罗列了fastjson内部所有已注册的反序列化实例(实际上是序列化实例)。下一步我将继续深入,解读每一个反序列化实例内部对token的使用(token的详情可以参考我的同学的文章:Fastjson源码分析—反序列化—Token的定义和解析(1)
下一期,特辑将继续,对几个主要的反序列化实例(BooleanCodec,CharacterCodec,IntegerCodec,FloatCodec,JavaBeanDeserializer)的实现逻辑展开分析
感谢各位老师的阅读与指导!

发表评论