美文网首页程序员
fastjson序列化原理简单分析

fastjson序列化原理简单分析

作者: 极微 | 来源:发表于2020-07-03 17:25 被阅读0次

    一、序列化概述

    • 序列化与反序列化概念
      序列化:将内存中的java对象转化为可供存储或可供传输的字节序列。
      反序列化:将字节序列转化为java对象。
    • 实现方式
      JDK原生的序列化与反序列化--需要实现Serializable接口。
      fastjson序列化与反序列化

    二、fastjson序列化解析

    以序列化Map对象为例
    JSON.toJSONString(map)
    发现最终调用的是JSON里面重载的toJSONString方法

    public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat, int defaultFeatures, SerializerFeature... features) {
            SerializeWriter out = new SerializeWriter((Writer)null, defaultFeatures, features);
    
            String var15;
            try {
                JSONSerializer serializer = new JSONSerializer(out, config);
                if (dateFormat != null && dateFormat.length() != 0) {
                    serializer.setDateFormat(dateFormat);
                    serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
                }
    
                if (filters != null) {
                    SerializeFilter[] var8 = filters;
                    int var9 = filters.length;
    
                    for(int var10 = 0; var10 < var9; ++var10) {
                        SerializeFilter filter = var8[var10];
                        serializer.addFilter(filter);
                    }
                }
    
                serializer.write(object);
                var15 = out.toString();
            } finally {
                out.close();
            }
    
            return var15;
        }
    

    跟踪serializer.write(object)方法,发现进入了MapSerializer的write方法。截取部分如下。

    if (entryKey instanceof String) {
        strEntryKey = (String)entryKey;
        if (!first) {
            out.write(44);
        }
    
        if (out.isEnabled(SerializerFeature.PrettyFormat)) {
            serializer.println();
        }
    
        out.writeFieldName(strEntryKey, true);
    } else {
        if (!first) {
            out.write(44);
        }
    
        if ((out.isEnabled(NON_STRINGKEY_AS_STRING) || SerializerFeature.isEnabled(features, SerializerFeature.WriteNonStringKeyAsString)) && !(entryKey instanceof Enum)) {
            strEntryKey = JSON.toJSONString(entryKey);
            serializer.write(strEntryKey);
        } else {
            serializer.write(entryKey);
        }
    
        out.write(58);
    }
    
    first = false;
    if (value == null) {
        out.writeNull();
    } else {
        Class<?> clazz = value.getClass();
        if (clazz != preClazz) {
            preClazz = clazz;
            preWriter = serializer.getObjectWriter(clazz);
        }
    
        if (SerializerFeature.isEnabled(features, SerializerFeature.WriteClassName) && preWriter instanceof JavaBeanSerializer) {
            Type valueType = null;
            if (fieldType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType)fieldType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                if (actualTypeArguments.length == 2) {
                    valueType = actualTypeArguments[1];
                }
            }
    
            JavaBeanSerializer javaBeanSerializer = (JavaBeanSerializer)preWriter;
            javaBeanSerializer.writeNoneASM(serializer, value, entryKey, valueType, features);
        } else {
            preWriter.write(serializer, value, entryKey, (Type)null, features);
        }
    }
    

    这个方法比较冗长,其大致意思是循环遍历Map的Entry,然后分别写入Entry的key和value。值得注意的是serializer.getObjectWriter(clazz)方法,即写入时会先获取value的class类型对应的writer进行写入。
    跟踪serializer.getObjectWriter(clazz)方法,当clazz为自定义类型,发现调用了SerializeConfig.createJavaBeanSerializer(Class<?> clazz)方法。

    public final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {
            String className = clazz.getName();
            long hashCode64 = TypeUtils.fnv1a_64(className);
            if (Arrays.binarySearch(this.denyClasses, hashCode64) >= 0) {
                throw new JSONException("not support class : " + className);
            } else {
                SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, (Map)null, this.propertyNamingStrategy, this.fieldBased);
                return (ObjectSerializer)
                  (beanInfo.fields.length == 0 && 
                  Iterable.class.isAssignableFrom(clazz) ? MiscCodec.instance : 
                  this.createJavaBeanSerializer(beanInfo));
            }
        }
    

    其中TypeUtils.buildBeanInfo方法获取clazz的所有属性并创建一个beanInfo对象,并调用createJavaBeanSerializer(beanInfo)方法构造一个ObjectSerializer对象返回。
    继续跟踪createJavaBeanSerializer(beanInfo),发现其最终返回了new JavaBeanSerializer(beanInfo),其主要属性如下

        protected final FieldSerializer[] getters;
        protected final FieldSerializer[] sortedGetters;
        protected SerializeBeanInfo beanInfo;
    

    我们再跳回到MapSerializer的write方法,那么自定义类型时调用preWriter 写入的时候就是调用的JavaBeanSerializer的write方法。跟踪这个方法。

    SerializeWriter out = serializer.out;
    .
    .
    .
    for(int i = 0; i < getters.length; ++i) {
          Field field = fieldSerializer.fieldInfo.field;
          FieldInfo fieldInfo = fieldSerializer.fieldInfo;
          out.write(fieldInfo.name_chars, 0, fieldInfo.name_chars.length);
    }
    

    其中会遍历其getters(若有排序则遍历sortedGetters),获取对象的每个属性,并调用out对象序列化输出属性名称和属性值。
    到现在为止,我们大体清楚了fastjson序列化了哪些内容,下面再看下是怎么实现的。其关键是SerializeWriter对象。继续跟踪out.write(fieldInfo.name_chars, 0, fieldInfo.name_chars.length)方法。

    public void write(char[] c, int off, int len) {
            if (off >= 0 && off <= c.length && len >= 0 && off + len <= c.length && off + len >= 0) {
                if (len != 0) {
                    int newcount = this.count + len;
                    if (newcount > this.buf.length) {//新的char[]实际长度>buf容量
                        if (this.writer == null) {
                            this.expandCapacity(newcount);//未指定writer则扩容
                        } else {
                            do {
                                int rest = this.buf.length - this.count;
                                System.arraycopy(c, off, this.buf, this.count, rest);
                                this.count = this.buf.length;
                                this.flush();//指定了writer则通过writer写出
                                len -= rest;
                                off += rest;
                            } while(len > this.buf.length);//剩余部分通过arraycopy拷贝到buf中
    
                            newcount = len;
                        }
                    }
    
                    System.arraycopy(c, off, this.buf, this.count, len);
                    this.count = newcount;
                }
            } else {
                throw new IndexOutOfBoundsException();
            }
        }
    
    public String toString() {
            return new String(this.buf, 0, this.count);
    }
    

    可以看出序列化的时候所有内容都保存在SerializeWriter的buf数组对象中,count就是buf的实际长度,JSON.toJSONString实际调用的是SerializeWriter的toString方法,展示的是bug这个字节数组。需要注意的是如果指定了writer对象,buf超长的情况下,toString展示的只是一部分序列化内容。

    三、UML类图

    相关文章

      网友评论

        本文标题:fastjson序列化原理简单分析

        本文链接:https://www.haomeiwen.com/subject/bstrfktx.html