安卓移动架构12-手写FastJson框架

安卓移动架构12-手写FastJson框架

FastJson官方地址:https://github.com/alibaba/fastjson

FastJson当前版本:1.1.68.android

这是一位大神手写的Json解析框架:ToolJson,是FastJson框架的简化版,只支持对JavaBean和List的序列化与反序列化。

学习这个框架的目的是,为了更好地理解FastJson框架。

下面为大家分享这个框架。

使用

先来看ToolJson的使用。

ToolJson的使用和FastJson基本一样:

public void testJson(View view) {
    StringBuilder result = new StringBuilder();//结果

    String json1 = JSON.toJSONString(child1);
    child1 = JSON.parse(json1, Parent.Child.class);
    result.append("序列化对象:" + json1);
    result.append("\n反序列化对象:" + child1);

    String json2 = JSON.toJSONString(list1);
    list1 = JSON.parse(json2, new TypeReference>() {
    }.getType());
    result.append("\n\n序列化集合:" + json2);
    result.append("\n反序列化集合:" + list1);

    String json3 = JSON.toJSONString(list3);
    list3 = JSON.parse(json3, new TypeReference>>() {
    }.getType());
    result.append("\n\n序列化复杂集合:" + json3);
    result.append("\n反序列化复杂集合:" + list3);

    showResult.setText(result.toString());
}

解析结果如下:

序列化对象:{"age":101,"name":"王1","test":1,"list":["1","2"]}
反序列化对象:Child{name='王1', age=101, list=[1, 2], childs=null}
                                                        
序列化集合:[{"age":101,"name":"王1","test":1,"list":["1","2"]},{"age":102,"name":"王2","test":1,"list":["1","2"]}]
反序列化集合:[Child{name='王1', age=101, list=[1, 2], childs=null}, Child{name='王2', age=102, list=[1, 2], childs=null}]
                                                        
序列化复杂集合:[[{"age":101,"name":"王1","test":1,"list":["1","2"]},{"age":102,"name":"王2","test":1,"list":["1","2"]}],[{"age":103,"name":"王3","test":1,"list":["1","2"]},{"age":104,"name":"王4","test":1,"list":["1","2"]}]]
反序列化复杂集合:[[Child{name='王1', age=101, list=[1, 2], childs=null}, Child{name='王2', age=102, list=[1, 2], childs=null}], [Child{name='王3', age=103, list=[1, 2], childs=null}, Child{name='王4', age=104, list=[1, 2], childs=null}]]

然后,我们来测试对比ToolJson的解析速度:

public void testFast(View view) {
    StringBuilder result = new StringBuilder();//结果

    start = System.currentTimeMillis();
    String json1 = JSON.toJSONString(child1);
    result.append("ToolJson序列化对象耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    String json2 = com.alibaba.fastjson.JSON.toJSONString(child1);
    result.append("\nFastJson反序列化对象耗时:" + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    child1 = JSON.parse(json1, Parent.Child.class);
    result.append("\n\nToolJson反序列化对象耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    child1 = com.alibaba.fastjson.JSON.parseObject(json2, Parent.Child.class);
    result.append("\nFastJson反序列化对象耗时:" + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    String json3 = JSON.toJSONString(list1);
    result.append("\n\nToolJson序列化集合耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    String json4 = com.alibaba.fastjson.JSON.toJSONString(list1);
    result.append("\nFastJson序列化集合耗时:" + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    list1 = JSON.parse(json3, new TypeReference>() {
    }.getType());
    result.append("\n\nToolJson反序列化集合耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    list1 = com.alibaba.fastjson.JSON.parseObject(json4, new com.alibaba.fastjson
            .TypeReference>() {
    }.getType());
    result.append("\nFastJson反序列化集合耗时:" + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    JsonRoot parse1 = JSON.parse(bigJson, JsonRoot.class);
    result.append("\n\nToolJson反序列化大数据耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    JsonRoot parse2 = com.alibaba.fastjson.JSON.parseObject(bigJson, JsonRoot.class);
    result.append("\nFastJson反序列化大数据耗时:" + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    String json5 = JSON.toJSONString(parse1);
    result.append("\n\nToolJson序列化大数据耗时:" + (System.currentTimeMillis() - start));
    start = System.currentTimeMillis();
    String json6 = com.alibaba.fastjson.JSON.toJSONString(parse2);
    result.append("\nFastJson序列化大数据耗时:" + (System.currentTimeMillis() - start));

    showResult.setText(result.toString());
}

第一次解析速度如下:

ToolJson序列化对象耗时:0
FastJson反序列化对象耗时:21

ToolJson反序列化对象耗时:0
FastJson反序列化对象耗时:6

ToolJson序列化集合耗时:0
FastJson序列化集合耗时:1

ToolJson反序列化集合耗时:2
FastJson反序列化集合耗时:3

ToolJson反序列化大数据耗时:82
FastJson反序列化大数据耗时:179

ToolJson序列化大数据耗时:79
FastJson序列化大数据耗时:106

第二次解析速度如下:

ToolJson序列化对象耗时:0
FastJson反序列化对象耗时:0

ToolJson反序列化对象耗时:1
FastJson反序列化对象耗时:0

ToolJson序列化集合耗时:0
FastJson序列化集合耗时:0

ToolJson反序列化集合耗时:2
FastJson反序列化集合耗时:1

ToolJson反序列化大数据耗时:51
FastJson反序列化大数据耗时:45

ToolJson序列化大数据耗时:21
FastJson序列化大数据耗时:27

很明显,第二次的解析速度比第一次快很多。这是因为ToolJson和FastJson在解析时,都做了缓存。

下面,来看ToolJson怎么实现序列化的。

序列化

序列化即将对象转为json格式的字符串。

序列化的原理:获取对象的公共属性,将属性的key和value,以json格式拼接到字符串中。

序列化会调用Json.toJSONString(),然后调用ObjectSerializer.serializer()。

public static String toJSONString(Object object) {
    ObjectSerializer serializer = JsonConfig.getGlobalInstance().getSerializer(object.getClass());
    StringBuilder sb = new StringBuilder();
    serializer.serializer(JsonConfig.getGlobalInstance(), sb, object);
    return sb.toString();
}

在FastJson中,ObjectSerializer是直接new出来的;在ToolJson中,ObjectSerializer是从JsonConfig获取的;

为什么要用JsonConfig呢?因为JsonConfig是用来缓存ObjectSerializer和ObjectDeserializer的,可以提升性能。

/**
 * 根据Class获取对应的序列化器
 *
 * @param clazz 对象的类型
 * @return 对应的序列化器
 */
public ObjectSerializer getSerializer(Class clazz) {
    ObjectSerializer objectSerializer = serializers.get(clazz);
    if (null != objectSerializer) {
        return objectSerializer;
    }
    if (List.class.isAssignableFrom(clazz)) {//判断对象是否List类型
        //ListSerializer实际是调用ObjectSerializer实现序列化,所以使用单例
        objectSerializer = ListSerializer.instance;
    } else if (Map.class.isAssignableFrom(clazz)) {
        throw new RuntimeException("Map序列化未实现");
    } else if (clazz.isArray()) {//判断对象是否数组
        throw new RuntimeException("数组序列化未实现");
    } else {
        objectSerializer = new JavaBeanSerializer(clazz);
    }
    serializers.put(clazz, objectSerializer);
    return objectSerializer;
}

本框架中,只实现了两种序列化器:JavaBeanSerializer和ListSerializer。

1 JavaBeanSerializer

JavaBean(实体类):专门用来存放可访问属性的类。可访问属性是指public属性或提供get、set方法的属性。

JavaBeanSerializer是JavaBean的序列化器。

JavaBeanSerializer创建时,会获取获得需要序列化的成员,这里使用FieldSerializer表示需要序列化的员。

public JavaBeanSerializer(Class clazz) {
    this.beanType = clazz;
    Map fieldCacheMap = new HashMap<>();
    //获得对于class及父class所有的成员属性
    Utils.parserAllFieldToCache(fieldCacheMap, beanType);
    //获得需要反序列化的成员
    fieldSerializers = Utils.computeGetters(beanType, fieldCacheMap);
}

需要序列化的成员,会先调用Utils.parserAllFieldToCache()获取获得对于class及父class所有的成员属性:先获取自己的成员属性,然后递归获取父类的成员属性。

/**
 * 获得对于class及父class所有的成员属性
 *
 * @param clazz
 * @return
 */
public static Map parserAllFieldToCache(Map fieldCacheMap, Class clazz) {
    //获得自己的所有属性
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        String fieldName = field.getName();
        if (!fieldCacheMap.containsKey(fieldName)) {
            fieldCacheMap.put(fieldName, field);
        }
    }
    //查找父类 的属性
    if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
        parserAllFieldToCache(fieldCacheMap, clazz.getSuperclass());
    }
    return fieldCacheMap;
}

然后根据class及父class所有的成员属性,获取需要序列化的成员。首先,遍历所有的公有方法,找到isget开头的方法,比较是否与成员属性名对应,如果对应,则是需要序列化的成员;然后,获取非静态的公有属性,也是需要序列化的成员。

/**
 * 从fieldCacheMap中获得需要序列化的成员
 * 包括: 当前类与父类的get函数、public成员属性
 *
 * @param clazz         对象的Class
 * @param fieldCacheMap class及父class所有的成员属性
 */
public static List computeGetters(Class clazz, Map fieldCacheMap) {
    Map fieldInfoMap = new LinkedHashMap<>();
    //类(父类) 所有的公有函数
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        String methodName = method.getName();
        //不要static
        if (Modifier.isStatic(method.getModifiers())) {
            continue;
        }
        //不要返回值是void
        if (method.getReturnType().equals(Void.TYPE)) {
            continue;
        }
        //不要参数
        if (method.getParameterTypes().length != 0) {
            continue;
        }
        // 不要getClass
        if (methodName.equals("getClass")) {
            continue;
        }
        String propertyName;
        // getA
        if (methodName.startsWith("get")) {
            //必须4个或者4个字符以上的函数名
            if (methodName.length() < 4) {
                continue;
            }
            //get后的第一个字母
            char c3 = methodName.charAt(3);
            // A-> age
            propertyName = Character.toLowerCase(c3) + methodName.substring(4);
            //可能拿到null
            Field field = fieldCacheMap.get(propertyName);
            FieldInfo fieldInfo = new FieldInfo(propertyName, method, field);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
        //获取布尔值的方法名以is开头
        if (methodName.startsWith("is")) {
            if (methodName.length() < 3) {
                continue;
            }
            //不是boolean或者Boolean
            if (method.getReturnType() != Boolean.TYPE && method.getReturnType() != Boolean.class) {
                continue;
            }
            char c2 = methodName.charAt(2);
            propertyName = Character.toLowerCase(c2) + methodName.substring(3);
            //可能已经在get找到了
            if (fieldInfoMap.containsKey(propertyName)) {
                continue;
            }
            Field field = fieldCacheMap.get(propertyName);
            FieldInfo fieldInfo = new FieldInfo(propertyName, method, field);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }
    //所有的公有成员
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
        //静态的不要
        if (Modifier.isStatic(field.getModifiers())) {
            continue;
        }
        String propertyName = field.getName();
        //把公有成员也加入json
        if (!fieldInfoMap.containsKey(propertyName)) {
            FieldInfo fieldInfo = new FieldInfo(propertyName, null, field);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }
    //
    List fieldInfos = new ArrayList<>();
    //fieldinfo加入到list集合中
    for (FieldInfo fieldInfo : fieldInfoMap.values()) {
        fieldInfos.add(new FieldSerializer(fieldInfo));
    }
    return fieldInfos;
}

序列化时,会去掉静态属性和方法。因为序列化时,只是修改内存中的值,不会修改类文件的类,即不会修改静态属性。

JavaBeanSerializer序列化对象是调用serializer(),实际上是遍历调用FieldSerializer.serializer(),拼接json格式的字符串。

public void serializer(JsonConfig config, StringBuilder out, Object object) {
    out.append("{");
    //上个属性是否为空
    boolean lastEmpty = true;
    for (FieldSerializer fieldSerializer : fieldSerializers) {
        //如果当前属性为空,则返回""
        String serializer = fieldSerializer.serializer(config, object);
        //如果上个属性非空,并且当前属性非空,则先拼接','
        if (!lastEmpty && !serializer.isEmpty()) {
            out.append(",");
        }
        //如果上个属性非空,则下一个属性是否拼接',',与当前属性是否为空无关;如果上个属性为空,则下一个属性是否拼接',',与当前属性是否为空有关
        if (lastEmpty) {
            lastEmpty = serializer.isEmpty();
        }
        out.append(serializer);
    }
    out.append("}");
}

FieldSerializer是属性序列化器,序列化属性时,如果是基本类型或string类型,则直接拼接;如果是JavaBean或List类型,则调用ObjectSerializer.serializer()继续序列化。

public String serializer(JsonConfig config, Object object) {
    Object o = fieldInfo.get(object);
    //属性没有值
    if (null == o) {
        return "";
    }
    StringBuilder sb = new StringBuilder();
    if (isPrimitive) {//基本类型
        sb.append(key);
        sb.append(o);
    } else if (Utils.isString(fieldInfo.type)) {//string类型
        sb.append(key);
        sb.append("\"");
        sb.append(o);
        sb.append("\"");
    } else {//JavaBean或List类型
        ObjectSerializer serializer = config.getSerializer(fieldInfo.type);
        sb.append(key);
        serializer.serializer(config, sb, o);
    }
    return sb.toString();
}

2 ListSerializer

ListSerializer是List的序列化器。

ListSerializer序列化List,会调用serializer(),遍历元素,如果是基本类型或string类型,则直接拼接;如果是JavaBean或List类型,则调用ObjectSerializer.serializer()继续序列化。

public void serializer(JsonConfig config, StringBuilder out, Object object) {
    List list = (List) object;
    if (list.isEmpty()) {
        out.append("[]");
        return;
    }
    out.append("[");
    for (int i = 0; i < list.size(); i++) {
        if (i != 0) {
            out.append(',');
        }
        Object item = list.get(i);
        if (null == item) {
            out.append("null");
        } else {
            Class clazz = item.getClass();
            if (Utils.isBox(clazz)) {//基本类型
                out.append(item);
            } else if (Utils.isString(clazz)) {//字符串类型
                out.append("\"");
                out.append(item);
                out.append("\"");
            } else {//JavaBean或List类型
                ObjectSerializer serializer = config.getSerializer(clazz);
                serializer.serializer(config, out, item);
            }
        }
    }
    out.append("]");
}

反序列化

反序列化是将json格式的字符串转为对象。

反序列化的原理:先将json字符串转为JsonObject,然后获取对象的公共属性,用JsonObject中的同名属性给对象的公共属性赋值。

注意:FastJson是将json字符串转为JSONLexer。

反序列化会调用JSON.parse(),然后调用ObjectDeserializer.deserializer()。

public static  T parse(String json, Type type) {
    ObjectDeserializer deserializer = JsonConfig.getGlobalInstance().getDeserializer(type);
    try {
        return deserializer.deserializer(JsonConfig.getGlobalInstance(), json, null);
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    return null;
}

ObjectDeserializer是从JsonConfig的缓存中获取的,分为两种:JavaBeanDeserializer、ListDeserializer。

public ObjectDeserializer getDeserializer(Type type) {
    ObjectDeserializer objectDeserializer = deserializers.get(type);
    if (null != objectDeserializer) {
        return objectDeserializer;
    }
    if (type instanceof Class) {
        objectDeserializer = new JavaBeanDeserializer((Class) type);
    } else if (type instanceof ParameterizedType) {
        objectDeserializer = new ListDeserializer((ParameterizedType) type);
    }
    deserializers.put(type, objectDeserializer);
    return objectDeserializer;
}

1 JavaBeanDeserializer

JavaBeanDeserializer是JavaBean的反序列化器。

JavaBeanDeserializer构建时,会获得需要反序列化的成员。

public JavaBeanDeserializer(Class clazz) {
    this.beanType = clazz;
    Map fieldCacheMap = new HashMap<>();
    //获得对于class及父class所有的成员属性
    Utils.parserAllFieldToCache(fieldCacheMap, beanType);
    //获得需要反序列化的成员
    fieldInfos = Utils.computeSetters(beanType, fieldCacheMap);
}

JavaBeanDeserializer获得需要反序列化的成员,会调用Utils.computeSetters()。首先,遍历所有的公有方法,找到set开头的方法,比较是否与成员属性名对应,如果对应,则是需要序列化的成员;然后,获取非静态的公有属性,也是需要序列化的成员。

public static List computeSetters(Class clazz, Map fieldCacheMap) {
    Map fieldInfoMap = new LinkedHashMap<>();
    //类(父类) 所有的公有函数
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        String methodName = method.getName();
        if (Modifier.isStatic(method.getModifiers())) {
            continue;
        }
        if (!method.getReturnType().equals(Void.TYPE)) {
            continue;
        }
        if (method.getParameterTypes().length != 1) {
            continue;
        }
        String propertyName;
        if (methodName.startsWith("set")) {
            if (methodName.length() < 4) {
                continue;
            }
            //set后的第一个字母
            char c3 = methodName.charAt(3);
            propertyName = Character.toLowerCase(c3) + methodName.substring(4);
            Field field = fieldCacheMap.get(propertyName);
            FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, true);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }

    //所有的public成员
    for (Field field : clazz.getFields()) {
        int modifiers = field.getModifiers();
        //静态和final的不要
        if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
            continue;
        }
        String propertyName = field.getName();
        //把公有成员也加入
        if (!fieldInfoMap.containsKey(propertyName)) {
            FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, true);
            fieldInfoMap.put(propertyName, fieldInfo);
        }
    }


    List fieldInfos = new ArrayList<>();
    //fieldinfo加入到list集合中
    for (FieldInfo fieldInfo : fieldInfoMap.values()) {
        fieldInfos.add(fieldInfo);
    }
    return fieldInfos;
}

JavaBeanDeserializer反序列化对象,会调用deserializer()。首先,将json格式的字符串转为JSONObject;然后,变量成员属性,从JSONObject获取对应的value,如果获取的value是基本类型或string类型,则直接给反序列化对象复制;如果获取的value是JavaBean或List类型,则调用ObjectDeserializer.deserializer()继续反序列化。

public  T deserializer(JsonConfig config, String json, Object object) throws Throwable {
    JSONObject jsonObject;
    if (null == object) {
        jsonObject = new JSONObject(json);
    } else {
        jsonObject = (JSONObject) object;
    }
    T t = null;
    try {
        t = (T) beanType.newInstance();
    } catch (Exception e) {
        e.printStackTrace();
    }
    //遍历属性,给属性赋值
    for (FieldInfo fieldInfo : fieldInfos) {
        //json数据中没有对应的key
        if (!jsonObject.has(fieldInfo.name)) {
            continue;
        }
        Object value = jsonObject.get(fieldInfo.name);
        if (value instanceof JSONObject || value instanceof JSONArray) {//JavaBean或List类型
            ObjectDeserializer deserializer = config.getDeserializer(fieldInfo.genericType);
            Object obj = deserializer.deserializer(config, null, value);
            fieldInfo.set(t, obj);
        } else {//基本类型或string类型
            if (value != JSONObject.NULL) {
                fieldInfo.set(t, value);
            }
        }
    }

    return t;
}

2 ListDeserializer

ListDeserializer是List的反序列化器。

ListDeserializer反序列化List,会调用deserializer()。首先,将json格式的字符串转为JSONArray;然后,遍历JSONArray,如果JSONArray的子项是基本类型或string类型,则直接添加到反序列化的List中;如果JSONArray的子项是JavaBean或List类型,则调用ObjectDeserializer.deserializer()继续反序列化。

public  T deserializer(JsonConfig config, String json, Object object) throws Throwable {
    JSONArray jsonArray;
    if (null == object) {
        jsonArray = new JSONArray(json);
    } else {
        jsonArray = (JSONArray) object;
    }

    List list = new ArrayList();

    //解析list item
    for (int i = 0; i < jsonArray.length(); i++) {
        //
        Object itemObj = jsonArray.get(i);
        if (itemObj instanceof JSONArray || itemObj instanceof JSONObject) {
            //获得泛型类型
            Type itemType = Utils.getItemType(type);
            ObjectDeserializer deserializer = config.getDeserializer(itemType);
            Object item = deserializer.deserializer(config, null, itemObj);
            list.add(item);
        } else {
            list.add(itemObj);
        }
    }

    return (T) list;
}

FastJson的小技巧

1 提升解析性能

提升解析性能,有以下方法:

  1. 缓存Class:解析之前,先缓存Class

    SerializeConfig.getGlobalInstance().registerIfNotExists(Child.class);
    ParserConfig.getGlobalInstance().registerIfNotExists(Child.class);
    
  2. 优先使用getter、setter,而不是public的field。因为解析时优先解析getter、setter。

  3. 使用@JSONField配置

  4. 使用@JSONType配置

2 注解的使用

FastJson在进行操作时,优先根据getter和setter的方法进行的,之后再依据PUBLIC Field进行。
1、@JSONType
​ 定义类的序列化
​ 指定忽略某个字段: {@JSONType(ignores = {"c_name"})}

2、@JSONField
​ 定义属性序列化Key
​ 作用在Fileld上
​ 针对 json数据的 Key与JavaBean 中的属性不能匹配,可以使用@JSONField进行解释
​ 作用在setter和getter方法上
​ getter表示 序列化后的Key; setter表示 反序列化对应的Key
​ 作用在函数参数上
​ 配合 @JSONCreator 使用

3、@JSONCreator
​ Fastjson在反序列化时必须提供无参构造函数
​ 如果定义的构造函数都需要参数则需要使用 @JSONCreator 标明提供此构造函数用于反序列化
​ 同时由于构造函数中参数没有办法与类属性相匹配,所以可以配合 @JSONField 同时使用

3 FastJson的性能优化

FastJson在解析时,为了优化性能进行了如下操作:

  1. ThreadLocal: 在SerializeWriter/JSONScanner中使用ThreadLocal保存一个byte[]或char[],减少内存分配

    ThreadLocal会提供线程内部的局部变量,这种变量在线程的生命周期内起作用。
    在多线程环境下访问时能保证各个线程里的变量相对独立于其他线程内的变量
    使用如:writeInt 实际上使用了 Long.getChars不直接使用Long转String 为了将输出加入char[],而不是获得String
    
  2. IdentityHashMap:在ParserConfig/SerializeConfig中,使用IdentityHashMap保存Class/Method/Field/Constructor,降低反射开销

  3. SymbolTable:使用SymbolTable 缓存常用的关键字,减少字符串对象创建。因为 FastJson基于char操作在需要将char转变为String的时候,使用缓存避免创建新的字符串对象。

    SymbolTable内部使用String.intern(),向虚拟机字符串常量池中添加常量。
    

最后

代码:https://gitee.com/yanhuo2008/AndroidCommon/tree/master/ToolJson

你可能感兴趣的:(安卓移动架构12-手写FastJson框架)