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

本文主要是介绍研究使用FastJson把Java对象转JsonObject的效率问题,以及改进方案。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

构造了一个稍微复杂的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@Overridepublic 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@Overridepublic Object reSerialize() {return this;}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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生成代码的方式处理转换方法。这样做既简单又高效。

这篇关于研究使用FastJson把Java对象转JsonObject的效率问题,以及改进方案。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093136

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na