fastjson源码解析——反序列化(二)

2021SC@SDUSC

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

概要

上篇fastjson源码解析——反序列化(一)已经从最简单的用户APIparseObject方法介绍了反序列化的大框架,以及第一个根据具体类型查询反序列化实例的同名方法;其中读者也略微领略到fastjson严谨的程序结构和语言设计风格。


根据之前的分析,fastjson最关键的部分就是如何根据具体的数据类型查找到具体特定的反序列化实例。
本文对fastjson中,查找反序列化实例的parseObject方法的代码展开解析
现在,我们继续反序列化源码的探究之旅

正式开始

进入

ObjectDeserializer deserializer = config.getDeserializer(type);

为了便于读者阅读,方法编号继承于上篇fastjson源码解析——反序列化(一)

4. ObjectDeserializer getDeserializer(Type type)

这个方法从fastjson内部查找已经注册过的所有不同类型的反序列化实例
方法输入:
Type type
返回此类型的反序列化实例ObjectDeserializer

在这之中,也能看到阿里巴巴的开发者为了提高fastjson的转化效率而付出的努力。这也不难看出,fastjson可以获得benchmark的最高分,且从正式版本发布开始一直占据榜首。

public ObjectDeserializer getDeserializer(Type type) {
        //找到内部已经注册的type类型反序列化实例,找到即返回
        ObjectDeserializer deserializer = get(type);
        if (deserializer != null) {
            return deserializer;
        }

        if (type instanceof Class<?>) {
            //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];
                return getDeserializer(upperBoundType);
            }
        }
        //都无法匹配,默认执行JavaObjectDeserializer
        return JavaObjectDeserializer.instance;
    }

整个方法写的很简洁,而且尽可能早地返回,从根本上减少了程序执行一遍此方法的步数,而且前面分支判断语句中出现的类,覆盖了大部分Java类(Class<?>,ParameterizedType etc..),能让fastjson执行最后JavaObjectDeserializer的类很少,而JavaObjectDeserializer方法恰恰消耗资源较多;通过这样的操作,开发者让fastjson的资源占用大大降低,效率极高。
若按照我写的示例程序执行,People类属于Class<?>类型,会执行

getDeserializer((Class<?>) type, type)

方法,此方法特定处理了泛型类型,进入此方法

5. getDeserializer(Class<?> clazz, Type type)

这个方法很长,可以略过直接看代码后分析

这个方法是最具体的查询反序列化实例的方法,也最可以体现出效率至上的fastjson开发理念。

public ObjectDeserializer getDeserializer(Class<?> clazz, Type type) {
        //首先还是查找到内部已经存在的type的反序列化实例
        ObjectDeserializer deserializer = get(type);
        if (deserializer == null && type instanceof ParameterizedTypeImpl) {
            Type innerType = TypeReference.intern((ParameterizedTypeImpl) type);
            deserializer = get(innerType);
        }

        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.") //awt的类
            && AwtCodec.support(clazz)) {
            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)) {
                            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)) {
                            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)) {
                            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 {
            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 mixInType = (Class) JSON.getMixInAnnotations(clazz);

            Class<?> deserClass = null;
            JSONType jsonType = TypeUtils.getAnnotation(mixInType != null ? mixInType : clazz, JSONType.class);

            if (jsonType != null) {
                deserClass = jsonType.deserializer();
                try {
                    deserializer = (ObjectDeserializer) deserClass.newInstance();
                    putDeserializer(clazz, deserializer);
                    return deserializer;
                } catch (Throwable error) {
                    // skip
                }
            }

            Method jsonCreatorMethod = null;
            if (mixInType != null) {
                Method mixedCreator = getEnumCreator(mixInType, clazz);
                if (mixedCreator != null) {
                    try {
                        jsonCreatorMethod = clazz.getMethod(mixedCreator.getName(), mixedCreator.getParameterTypes());
                    } catch (Exception e) {
                        // skip
                    }
                }
            } else {
                jsonCreatorMethod = getEnumCreator(clazz, clazz);
            }

            if (jsonCreatorMethod != null) {
                deserializer = new EnumCreatorDeserializer(jsonCreatorMethod);
                putDeserializer(clazz, deserializer);
                return deserializer;
            }

            deserializer = getEnumDeserializer(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) {//集合类型
            deserializer = CollectionCodec.instance;
        } else if (Collection.class.isAssignableFrom(clazz)) {//Collection类型
            deserializer = CollectionCodec.instance;
        } else if (Map.class.isAssignableFrom(clazz)) {//Map类型
            deserializer = MapDeserializer.instance;
        } else if (Throwable.class.isAssignableFrom(clazz)) {//Throwable类型
            deserializer = new ThrowableDeserializer(this, clazz);
        } else if (PropertyProcessable.class.isAssignableFrom(clazz)) {
            deserializer = new PropertyProcessableDeserializer((Class<PropertyProcessable>) clazz);
        } else if (clazz == InetAddress.class) {
            deserializer = MiscCodec.instance;
        } else {//默认执行JavaBean类型的反序列化
            deserializer = createJavaBeanDeserializer(clazz, type);
        }
        //添加到注册的反序列化类型中,避免出现重复创建反序列化器
        putDeserializer(type, deserializer);

        return deserializer;
    }

这段代码很长,看下来的都不容易(偷笑)
主要介绍了反序列化器对继承了各种常见类、接口的类,如何将其对应到特定此类型的反序列化工具中,大致写了awt.*,time.*,Array,Map,Collection等常用类的对应。
关键在于,将类的名字截取,匹配上前两种类;再利用类的层级关系,匹配特殊的类型,如Map等。若已注册的反序列化实例中无法找到需要的反序列化类型,程序不得不创建此类型的实例,但是一旦创建后,程序便将其写入cache,便于下次的调用。第一次调用时开销大,第二次之后的每次调用都几乎不需要开销,可以快速反序列化,在时间复杂性分析上,程序是O(n+a)的时间复杂性,线性函数,大大降低了调用成本(与之对比,若每次都新建反序列化实例,时间复杂性则增大到O(n^2),二次函数)
采用这样的程序编写技巧,降低了高开销方法的执行次数,也降低了程序的步数,用微不足道的空间复杂性增加,换取了极大的时间上的性能。这样的编程思路可以进一步体悟理解。

最后

fastjson反序列化的部分暂时介绍到这里。本文从fastjson对具体类型的反序列化实例查找开始,介绍到如何匹配继承了某些常用类的具体反序列化实例。
在本次旅途中,我们既可以学习反序列化的操作逻辑,也可以透过代码看到阿里巴巴开发者的巧思,能让我们看到对程序效率的极致追求。这对我们尤其重要,我们平时写程序,尤其是项目,都是本着能用就行的借口,直接忽视了对服务器高并发、自动化部署、安全性健壮性测试的需要,实际上这些内容在实际工作中极为重要;我在暑假实习的期间就深深感到性能优化对SQL数据库查询的重要性,服务器等更是如此。在未来的学习中,我们也应该相对倾斜一部分精力考虑性能优化的方式。
下次我计划从这里开始,分析

deserializer = createJavaBeanDeserializer(clazz, type);

这个方法如何处理普通(并没有继承那些常用类)的类
感谢各位老师的阅读与指导!

发表评论