fastJSON源码分析_2_对象序列化器的获取

本文深入探讨了JSON序列化过程中对象序列化器的获取方式,重点关注了SerializeConfig类及其全局实例globalInstance。文章详细分析了getObjectWriter方法,该方法根据对象的class类型从内部维护的map中查找或生成相应的ObjectSerializer。初始化过程涉及多种数据类型及其对应的Codec实例,确保了序列化的高效性和泛用性。此外,还介绍了如何通过类类型、自动装配对象、模块和各种类型的序列化器进行判断和处理。

2021SC@SDUSC

 本篇简介

上一篇文章中,我们浅析了writeJSONString一个大致的处理顺序以及它的代码结构和作用,字符流输出的大致结构和它相仿,所以我们更加关注字节流及字符流的更加深入的实现.

我们在上一篇文章中提到过关于ObjectSerializer这个接口,它的主要作用便是提供了write方法接口来帮助具体类实现序列化的功能.也就是对应的如下代码:

        Class<?> clazz = object.getClass();//获取对象的class元信息
        ObjectSerializer writer = getObjectWriter(clazz);//初始化对象序列化器

        try {
            writer.write(this, object, null, null, 0);//调用write方法
        } catch (IOException e) {
            throw new JSONException(e.getMessage(), e);
        }

本篇内容将会关注于该类的具体实现类的获取方式.

源码分析

我们主要分析的源码是SerializeConfig的结构以及getObjectWriter具体的实现方法.

SerializeConfig

在上一篇中我们知道了,ObjectSrializer的具体实现类的获取是根据getObjectWriter(Class)来初始化的.

getObjectWriter方法是由JSONSerializer类所维护的SerializeConfig来实现的,当我们在调用writeJSONString方法的时候,SerializeConfig是作为了该方法的一个参数类型,而该参数默认是一个静态的值SerializeConfig.globalInstance,也就是全局定义的一个配置实例.

我们去看SerializeConfig的内容,其实globalInstance就是一个无参的SerializeConfig对象.

 但是无参的构造函数最终又调用了有参的构造函数,参数分别为tableSize:int,和fieldBase:boolean.

 我们可以看到,SerilizeConfig维护了两个map,也就是重新编写的IdentityHashMap,其中Serializers的大小为DEFAULT_SIZE(具体是8192),对应的key和value是<Type,ObjectSerializer>,可以很容易地猜到这是一个管理序列化器的map,而,mixInSerializers这个map则是一个管理这类map的map,大小为16.

这里我注意到了Type这个key类型,它是java反射库里定义的一个接口,是java所有的基本数据类型以及类所实现的接口,那为什么要用这样的类型作为key呢?往下看(跳过有关asm的内容,这不是本篇重点),我们注意到最后一段代码,调用对象序列化器的初始化方法,这里直接上源码:

 private void initSerializers() {
        put(Boolean.class, BooleanCodec.instance);
        put(Character.class, CharacterCodec.instance);
        put(Byte.class, IntegerCodec.instance);
        put(Short.class, IntegerCodec.instance);
        put(Integer.class, IntegerCodec.instance);
        put(Long.class, LongCodec.instance);
        put(Float.class, FloatCodec.instance);
        put(Double.class, DoubleSerializer.instance);
        put(BigDecimal.class, BigDecimalCodec.instance);
        put(BigInteger.class, BigIntegerCodec.instance);
        put(String.class, StringCodec.instance);
        put(byte[].class, PrimitiveArraySerializer.instance);
        put(short[].class, PrimitiveArraySerializer.instance);
        put(int[].class, PrimitiveArraySerializer.instance);
        put(long[].class, PrimitiveArraySerializer.instance);
        put(float[].class, PrimitiveArraySerializer.instance);
        put(double[].class, PrimitiveArraySerializer.instance);
        put(boolean[].class, PrimitiveArraySerializer.instance);
        put(char[].class, PrimitiveArraySerializer.instance);
        put(Object[].class, ObjectArrayCodec.instance);
        put(Class.class, MiscCodec.instance);

        put(SimpleDateFormat.class, MiscCodec.instance);
        put(Currency.class, new MiscCodec());
        put(TimeZone.class, MiscCodec.instance);
        put(InetAddress.class, MiscCodec.instance);
        put(Inet4Address.class, MiscCodec.instance);
        put(Inet6Address.class, MiscCodec.instance);
        put(InetSocketAddress.class, MiscCodec.instance);
        put(File.class, MiscCodec.instance);
        put(Appendable.class, AppendableSerializer.instance);
        put(StringBuffer.class, AppendableSerializer.instance);
        put(StringBuilder.class, AppendableSerializer.instance);
        put(Charset.class, ToStringSerializer.instance);
        put(Pattern.class, ToStringSerializer.instance);
        put(Locale.class, ToStringSerializer.instance);
        put(URI.class, ToStringSerializer.instance);
        put(URL.class, ToStringSerializer.instance);
        put(UUID.class, ToStringSerializer.instance);

        // atomic
        put(AtomicBoolean.class, AtomicCodec.instance);
        put(AtomicInteger.class, AtomicCodec.instance);
        put(AtomicLong.class, AtomicCodec.instance);
        put(AtomicReference.class, ReferenceCodec.instance);
        put(AtomicIntegerArray.class, AtomicCodec.instance);
        put(AtomicLongArray.class, AtomicCodec.instance);

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

        put(LinkedList.class, CollectionCodec.instance);
    }

这个方法应该是将map给初始化了,这里就直接用java提供的基本数据类型和常用数据类型的class,以及所对应的Codec实例(instance)组成键值对放入map中,这里就可以简单知道各种Codec的实例就是实现好的ObjectSerializer了.我们先将codec放在一边,回过来再看我们的getObjectSerializer方法,这个方法的名字直接表明了就是要返回一个对象序列化器,这个方法的直接实现方法为:

getObjectSerializer(clazz,create)

这个方法的代码量较大,但是可以很好地按照clazz的类型进行分类,

1.首先从初始化的基本类型序列化器map中寻找对应的序列化器,如果有,就直接返回.否则再继续判断.

2. 紧接着判断该clazz是否是自动装配对象的基本类型,这里的类加载器分别使用了当前线程的类加载器以及当前类(JSON)的类加载器

 3.接着是判断是否是Module中存在的clazz,这个是一个扩展模块,可以编写自己需要的序列化器模块

 4.然后是更加多类型的序列化器的判断(主要是接口类型及其实现),包括数组,列表,map,枚举类型等等.这里只上部分代码.

 isAssignablleFrom方法的含义是判(Class)是否是调用对象(Class)的接口或者父类.

5.再往下就是关于各种库的类型的支持包括awt,jdk8,jdbc等等.

总而言之

有关对象序列化器的获取框架就是通过对象的class类型,创建config对象,通过判断从维护的map中获取到相应的对象序列化实例,然后处理对象.不过序列化器map的组织方式有着很鲜明的特点,就是先放一点常用的数据类型让我们去取它们的序列化器,而不是全部在初始化时就放入map中,然后再通过进一步的判断,将clazz对应的序列化器动态地生成放入map中,再取出返回,并且由于config是静态的对象,map不需要每次用过后就再初始化,这样做既顾及了效率,同时也具有泛用性.下一篇我们将更加深入了解序列化的实现机制.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值