欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

研究使用FastJson把Java对象转JsonObject的效率问题,以及改进方案。

程序员文章站 2022-07-10 09:11:31
构造了一个稍微复杂的Java对象对比在不同情况下的转换效率,都是循环20次执行。https://gitee.com/icefire11/test-fast-json概述:Main方法示例:import com.alibaba.fastjson.JSONObject;public class Test { public static void main(String[] args) { School school = new School(); lon...

构造了一个稍微复杂的Java对象对比在不同情况下的转换效率,都是循环20次执行。

项目地址:https://gitee.com/icefire11/test-fast-json

概述:

Main方法示例:

import com.alibaba.fastjson.JSONObject;

public class Test {
    public static void main(String[] args) {
        School school = new School();
        long start = System.currentTimeMillis();

        for (int i = 0; i < 20; i++) {
            // 带过滤的方法
            JSONObject json = JsonUtils.toClientJSONObject(school);
            // 自定义转换规则
            //JSONObject json = (JSONObject)school.toJson();
            // 原生方法
            // Object json = JSONObject.toJSON(school);
        }
       // System.out.println(json);
        long end = System.currentTimeMillis();
        System.out.println("Time:" + (end - start) + "ms");
    }
}

构造的Java对象示例:

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.data.annotation.Transient;

/**
 * @desc: TODO
 * @author: zhangjiaqi
 * @time: 2020/11/25 11:55
 */
public class School implements ReSerializeModel{
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RString p1 = new RString("打卡的框架阿里1");
    RString p2 = new RString("打卡的框架阿里2");
    RString p3 = new RString("打卡的框架阿里3");
    RString p4 = new RString("打卡的框架阿里4");
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RString p5 = new RString("打卡的框架阿里5");

    RInteger p6 = new RInteger(1);
    RInteger p7 = new RInteger(2);
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RInteger p8 = new RInteger(3);
    RInteger p9 = new RInteger(4);
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RInteger p10 = new RInteger(5);


    RList<Article> list1 = new RList<>();
    RList<Book> list2 = new RList<>();
    RList<Student> list3 = new RList<>();
    RList<Teacher> list4 = new RList<>();

    RMap<Article> map1 = new RMap<>();
    RMap<Book> map2 = new RMap<>();
    RMap<Student> map3 = new RMap<>();
    RMap<Teacher> map4 = new RMap<>();

    public School(){
        list1.getList().add(new Article());
        list1.getList().add(new Article());
        list1.getList().add(new Article());
        list1.getList().add(new Article());
        list1.getList().add(new Article());
        list1.getList().add(new Article());
        list1.getList().add(new Article());

        list2.getList().add(new Book());
        list2.getList().add(new Book());
        list2.getList().add(new Book());
        list2.getList().add(new Book());
        list2.getList().add(new Book());
        list2.getList().add(new Book());

        list3.getList().add(new Student());
        list3.getList().add(new Student());
        list3.getList().add(new Student());
        list3.getList().add(new Student());
        list3.getList().add(new Student());
        list3.getList().add(new Student());
        list3.getList().add(new Student());

        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());
        list4.getList().add(new Teacher());

        map1.getMap().put("1", new Article());
        map1.getMap().put("2", new Article());
        map1.getMap().put("3", new Article());
        map1.getMap().put("4", new Article());
        map1.getMap().put("5", new Article());
        map1.getMap().put("6", new Article());
        map1.getMap().put("7", new Article());

        map2.getMap().put("1", new Book());
        map2.getMap().put("2", new Book());
        map2.getMap().put("3", new Book());
        map2.getMap().put("4", new Book());
        map2.getMap().put("5", new Book());
        map2.getMap().put("6", new Book());
        map2.getMap().put("7", new Book());

        map3.getMap().put("1", new Student());
        map3.getMap().put("2", new Student());
        map3.getMap().put("3", new Student());
        map3.getMap().put("4", new Student());
        map3.getMap().put("5", new Student());
        map3.getMap().put("6", new Student());
        map3.getMap().put("7", new Student());

        map4.getMap().put("1", new Teacher());
        map4.getMap().put("2", new Teacher());
        map4.getMap().put("3", new Teacher());
        map4.getMap().put("4", new Teacher());
        map4.getMap().put("5", new Teacher());
        map4.getMap().put("6", new Teacher());
        map4.getMap().put("7", new Teacher());
    }

    public RString getP1() {
        return p1;
    }

    ... 省去set get
    @Override
    public Object toJson() {
        JSONObject json = new JSONObject();
        json.put("p2", SerializaUtils.toJSON(p2));
        json.put("p3", SerializaUtils.toJSON(p3));
        json.put("p4", SerializaUtils.toJSON(p4));
        json.put("p6", SerializaUtils.toJSON(p6));
        json.put("p7", SerializaUtils.toJSON(p7));
        json.put("p8", SerializaUtils.toJSON(p8));

        json.put("list1", SerializaUtils.toJSON(list1));
        json.put("list2", SerializaUtils.toJSON(list2));
        json.put("list3", SerializaUtils.toJSON(list3));
        json.put("list4", SerializaUtils.toJSON(list4));
        json.put("map1", SerializaUtils.toJSON(map1));
        json.put("map2", SerializaUtils.toJSON(map2));
        json.put("map3", SerializaUtils.toJSON(map3));
        json.put("map4", SerializaUtils.toJSON(map4));
        return json;
        return json;
    }
}
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.data.annotation.Transient;

/**
 * @desc: TODO
 * @author: zhangjiaqi
 * @time: 2020/11/25 14:22
 */
public class Student implements ReSerializeModel{

    @Transient
    @JSONField(serialize = false, deserialize = false)
    RString p1 = new RString("打卡的框架阿里1");
    RString p2 = new RString("打卡的框架阿里2");
    RString p3 = new RString("打卡的框架阿里3");
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RString p4 = new RString("打卡的框架阿里4");
    RString p5 = new RString("打卡的框架阿里5");

    @Transient
    @JSONField(serialize = false, deserialize = false)
    RInteger p6 = new RInteger(1);
    RInteger p7 = new RInteger(2);
    RInteger p8 = new RInteger(3);
    @Transient
    @JSONField(serialize = false, deserialize = false)
    RInteger p9 = new RInteger(4);
    RInteger p10 = new RInteger(5);

    RList<Book> list1 = new RList<>();
    RList<Article> list2 = new RList<>();

    RMap<Book> map1 = new RMap<>();
    RMap<Article> map2 = new RMap<>();

    public Student(){
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());
        list1.getList().add(new Book());

        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());
        list2.getList().add(new Article());

        map1.getMap().put("1", new Book());
        map1.getMap().put("2", new Book());
        map1.getMap().put("3", new Book());
        map1.getMap().put("4", new Book());
        map1.getMap().put("5", new Book());
        map1.getMap().put("6", new Book());
        map1.getMap().put("7", new Book());
        map1.getMap().put("8", new Book());

        map2.getMap().put("1", new Article());
        map2.getMap().put("2", new Article());
        map2.getMap().put("3", new Article());
        map2.getMap().put("4", new Article());
        map2.getMap().put("5", new Article());
        map2.getMap().put("6", new Article());
        map2.getMap().put("7", new Article());
        map2.getMap().put("8", new Article());
    }

    public RString getP1() {
        return p1;
    }

    ... 省去 set和get

    @Override
    public Object reSerialize() {
        return this;
    }

    @Override
    public Object toJson() {
       JSONObject json = new JSONObject();
        json.put("p2", SerializaUtils.toJSON(p2));
        json.put("p3", SerializaUtils.toJSON(p3));
        json.put("p5", SerializaUtils.toJSON(p5));
        json.put("p7", SerializaUtils.toJSON(p7));
        json.put("p8", SerializaUtils.toJSON(p8));
        json.put("p10", SerializaUtils.toJSON(p10));


        json.put("list1", SerializaUtils.toJSON(list1));
        json.put("list2", SerializaUtils.toJSON(list2));
        json.put("map1", SerializaUtils.toJSON(map1));
        json.put("map2", SerializaUtils.toJSON(map2));
        return json;
    }
}


1 使用注解过滤掉一些字段(不想发给客户端,不想存库等)调用 JsonUtils.toClientJSONObject(Object obj)

调用方法:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public final class JsonUtils {

    public static final Map<Class<?>, Map<String, Boolean>> PR_IGNORE_FIELDS = new ConcurrentHashMap<>();
    public static final ValueFilter DPSVALUE_FILTER = new ValueFilter() {
        @Override
        public Object process(Object o, String propertyName, Object propertyValue) {
            if (propertyValue instanceof ReSerializeModel) {
                return ((ReSerializeModel) propertyValue).reSerialize();
            }
            return propertyValue;
        }
    };
    public static final PropertyFilter DPSPROPERTY_FILTER = new PropertyFilter() {
        @Override
        public boolean apply(Object object, String name, Object value) {
            Class<?> clz = object.getClass();
            PR_IGNORE_FIELDS.putIfAbsent(clz, new ConcurrentHashMap<>());
            Map<String, Boolean> clzIgnoreFields = PR_IGNORE_FIELDS.get(clz);
            if (!clzIgnoreFields.containsKey(name)) {
                Field field = ReflectUtils.getFieldWhatever(clz, name);
                if (field == null)
                    return true;
                clzIgnoreFields.put(name, field.isAnnotationPresent(ClientIgnore.class));
            }
            return !clzIgnoreFields.get(name);
        }
    };
    private JsonUtils(){

    }
    public static String toClientString(Object obj) {
        return JSON.toJSONString(obj, new SerializeFilter[] { DPSVALUE_FILTER, DPSPROPERTY_FILTER }, SerializerFeature.DisableCircularReferenceDetect);
    }


    public static JSONObject toClientJSONObject(Object obj) {
        String s = toClientString(obj);
        return JSON.parseObject(s);
    }
}

     执行结果:

Connected to the target VM, address: '127.0.0.1:54338', transport: 'socket'
Time:23180ms
Disconnected from the target VM, address: '127.0.0.1:54338', transport: 'socket'

Process finished with exit code 0

2 去掉带注解的过滤 调用 JsonUtils.toClientJSONObject(Object obj) 但 去掉了toClientString(Object obj) 里面的过滤规则

     执行结果:

Connected to the target VM, address: '127.0.0.1:54396', transport: 'socket'
Time:1323ms
Disconnected from the target VM, address: '127.0.0.1:54396', transport: 'socket'

Process finished with exit code 0

    调用方法: 注意下面的toClientString(Object obj)方法,里面去掉了注解过滤

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public final class JsonUtils {

    public static final Map<Class<?>, Map<String, Boolean>> PR_IGNORE_FIELDS = new ConcurrentHashMap<>();
    public static final ValueFilter DPSVALUE_FILTER = new ValueFilter() {
        @Override
        public Object process(Object o, String propertyName, Object propertyValue) {
            if (propertyValue instanceof ReSerializeModel) {
                return ((ReSerializeModel) propertyValue).reSerialize();
            }
            return propertyValue;
        }
    };
    public static final PropertyFilter DPSPROPERTY_FILTER = new PropertyFilter() {
        @Override
        public boolean apply(Object object, String name, Object value) {
            Class<?> clz = object.getClass();
            PR_IGNORE_FIELDS.putIfAbsent(clz, new ConcurrentHashMap<>());
            Map<String, Boolean> clzIgnoreFields = PR_IGNORE_FIELDS.get(clz);
            if (!clzIgnoreFields.containsKey(name)) {
                Field field = ReflectUtils.getFieldWhatever(clz, name);
                if (field == null)
                    return true;
                clzIgnoreFields.put(name, field.isAnnotationPresent(ClientIgnore.class));
            }
            return !clzIgnoreFields.get(name);
        }
    };
    private JsonUtils(){

    }
    public static String toClientString(Object obj) {
        return JSON.toJSONString(obj, new SerializeFilter[] { DPSVALUE_FILTER }, SerializerFeature.DisableCircularReferenceDetect);
    }


    public static JSONObject toClientJSONObject(Object obj) {
        String s = toClientString(obj);
        return JSON.parseObject(s);
    }
}

3 直接使用FastJson的  JSONObject.toJSON()方法,但是这样无法过滤掉一些字段
     执行结果:

Connected to the target VM, address: '127.0.0.1:54432', transport: 'socket'
Time:772ms
Disconnected from the target VM, address: '127.0.0.1:54432', transport: 'socket'

Process finished with exit code 0

4 使用自定义转换方法 调用对象中的toJson()方法

    自定义处理方法(由fastjson修改):

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;

import java.lang.reflect.Array;
import java.util.*;

/**
 * @desc: TODO
 * @author: zhangjiaqi
 * @time: 2020/11/27 17:08
 */
public class SerializaUtils {
    public static Object toJSON(Object javaObject) {
        if (javaObject == null) {
            return null;
        } else if (javaObject instanceof JSON) {
            return javaObject;
        } else {
            JSONObject json;
            int len;
            if (javaObject instanceof Map) {
                Map<Object, Object> map = (Map) javaObject;
                len = map.size();
                Object innerMap;
                if (map instanceof LinkedHashMap) {
                    innerMap = new LinkedHashMap(len);
                } else if (map instanceof TreeMap) {
                    innerMap = new TreeMap();
                } else {
                    innerMap = new HashMap(len);
                }
                json = new JSONObject((Map) innerMap);
                Iterator var24 = map.entrySet().iterator();
                while (var24.hasNext()) {
                    Map.Entry<Object, Object> entry = (Map.Entry) var24.next();
                    Object key = entry.getKey();
                    String jsonKey = TypeUtils.castToString(key);
                    Object jsonValue = toJSON(entry.getValue());
                    json.put(jsonKey, jsonValue);
                }
                return json;
            } else {
                if (javaObject instanceof Collection) {
                    Collection<Object> collection = (Collection) javaObject;
                    JSONArray array = new JSONArray(collection.size());
                    Iterator var19 = collection.iterator();
                    while (var19.hasNext()) {
                        Object item = var19.next();
                        item = toJSON(item);
                        array.add(item);
                    }
                    return array;
                } else if (javaObject instanceof ReSerializeModel) {
                    return ((ReSerializeModel) javaObject).toJson();
                } else {
                    Class<?> clazz = javaObject.getClass();
                    if (clazz.isEnum()) {
                        return ((Enum) javaObject).name();
                    } else if (clazz.isArray()) {
                        len = Array.getLength(javaObject);
                        JSONArray array = new JSONArray(len);
                        for (int i = 0; i < len; ++i) {
                            Object item = Array.get(javaObject, i);
                            Object jsonValue = toJSON(item);
                            array.add(jsonValue);
                        }
                        return array;
                    } else if (ParserConfig.isPrimitive2(clazz)) {
                        return javaObject;
                    } else {
                        // 未继承ReSerializeModel的未知对象 不进行转换
                        return null;
                    }
                }
            }
        }
    }
}


    执行结果:

Connected to the target VM, address: '127.0.0.1:57670', transport: 'socket'
Time:401ms
Disconnected from the target VM, address: '127.0.0.1:57670', transport: 'socket'

Process finished with exit code 0

 

结论:

       去掉注解过滤,转换效率是带注解过滤的近30倍,而直接使用fastjson的原生方法,不加任何其他规则,效率比不带注解过滤更快一些,这是显然对的,随着转换规则越来越少,转换效率越来越高,但是这其中的重点是加上注解过滤规则之后效率直接降低了近30倍,这在线上是很难接受的,这个Java对象还比较简单,真正游戏中用到的Java对象极其复杂,比如玩家对象,里面有玩家所有信息,这是一个很庞大的对象,使用带注解过滤的方式去处理这个对象,那效率简直是灾难。但是不加注解过滤,就无法过滤一些不想转json的字段,这也是不能接受的。

     我们想要效率高,又想要过滤一些字段,该怎么办,那就是使用自定义转换方法,把需要转换的字段写进方法里面,不需要转换的就不考虑,通过对比可以发现,这样做比直接使用原生Json不带任何规则还快了近1倍,时间只有其1/2,这样效率高,又能满足复杂规则的选择我们为什么不考虑呢,有人可能会说,这样会使写代码比较麻烦,我们可以把所有需要需要转换成Json的对象写在模板里面,通过FreeMarker生成代码的方式处理转换方法。这样做既简单又高效。

本文地址:https://blog.csdn.net/u012901117/article/details/110230305