👉 这是一个或许对你有用的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入芋道快速开发平台知识星球。下面是星球提供的部分资料:
👉这是一个或许对你有用的开源项目
国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。
功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号、CRM 等等功能:
  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

每次new一个

在SpringBoot项目中要实现对象与Json字符串的互转,每次都需要像如下一样new 一个ObjectMapper对象:
public UserEntity string2Obj(String json)throws JsonProcessingException 
{

        ObjectMapper objectMapper = 
new
 ObjectMapper();

return
 objectMapper.readValue(json, UserEntity
.class)
;

        }


public String obj2String(UserEntity userEntity)throws JsonProcessingException 
{

        ObjectMapper objectMapper = 
new
 ObjectMapper();

return
 objectMapper.writeValueAsString(car)

        }

这样的代码到处可见,有问题吗?
你要说他有问题吧,确实能正常执行;可你要说没问题吧,在追求性能的同学眼里,这属实算是十恶不赦的代码了。
首先,让我们用JMH对这段代码做一个基准测试,让大家对其性能有个大概的了解。
基准测试是指通过设计科学的测试方法、测试工具和测试系统,实现对一类测试对象的某项性能指标进行定量的和可对比的测试。而JMH是一个用来构建,运行,分析Java或其他运行在JVM之上的语言的 纳秒/微秒/毫秒/宏观 级别基准测试的工具。
@BenchmarkMode
(Mode.Throughput)

@OutputTimeUnit
(TimeUnit.SECONDS)

@State
(Scope.Thread)

@Fork
(
1
)

@Warmup
(iterations = 
5
, time = 
1
)

@Measurement
(iterations = 
3
, time = 
1
)

publicclassJsonJMHTest
{


    String json = 
"{\"id\":122345667,\"email\":\"[email protected]\",\"price\":12.25}"
;

    UserEntity userEntity = 
new
 UserEntity(
13345L
,
"[email protected]"
, BigDecimal.valueOf(
12.25
));

/**

     * 测试String to Object

     */

@Benchmark
public UserEntity objectMapper2ObjTest()throws JsonProcessingException 
{

        ObjectMapper objectMapper = 
new
 ObjectMapper();

return
 objectMapper.readValue(json, UserEntity
.class)
;

    }


/**

     * 测试Object to String

     */

@Benchmark
public String objectMapper2StringTest()throws JsonProcessingException 
{

        ObjectMapper objectMapper = 
new
 ObjectMapper();

return
 objectMapper.writeValueAsString(userEntity);

    }


publicstaticvoidmain(String[] args)throws RunnerException 
{

        Options opt = 
new
 OptionsBuilder()

                .include(JsonJMHTest
.
class
.
getSimpleName
())

                .
build
()
;

new
 Runner(opt).run();

    }

}

测试环境

> 基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

>

> * 项目地址:<https:
//github.com/YunaiV/ruoyi-vue-pro>
> * 视频教程:<https:
//doc.iocoder.cn/video/>

# JMH version: 
1.36
        # VM version: JDK 
17.0.3
, OpenJDK 
64
-Bit Server VM, 
17.0.3
+
7
-LTS

        # Mac AppleM1/
16
GB

测试结果
通过测试结果可以看出,每次new一个ObjectMapper,在实现字符串转对象时每秒可以完成23万多次,而实现对象转Json字符串每秒仅可完成2.7万次。
那该如何优化,提升性能呢?
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

单例化

老鸟们都知道,在创建工具类时要将工具类设置成单例的,这样不仅可以保证线程安全,也可以保证在系统全局只能创建一个对象,避免频繁创建对象的成本。
所以,我们可以在项目中构建一个ObjectMapper的单例类。
@Getter
publicenum
 ObjectMapperInstance {


    INSTANCE;


privatefinal
 ObjectMapper objectMapper = 
new
 ObjectMapper();


    ObjectMapperInstance() {


    }

}

再次使用JMH对其测试:
@Benchmark
public UserEntity singleten2ObjTest()throws JsonProcessingException 
{

        ObjectMapper objectMapper = ObjectMapperInstance.INSTANCE.getObjectMapper();

return
 objectMapper.readValue(json, UserEntity
.class)
;

        }


@Benchmark
public String singleten2StringTest()throws JsonProcessingException 
{

        ObjectMapper objectMapper = ObjectMapperInstance.INSTANCE.getObjectMapper();

return
 objectMapper.writeValueAsString(userEntity);

        }

测试结果如下:
可以看到,使用单例模式,String转对象的方法每秒可以执行420多万次,比new ObjectMapper的方式快了18倍;而对象转String的方法每秒可以执行830万次,性能提升了300倍(看到结果的一瞬间我傻眼了,一度怀疑是写错代码了)!!!!

个性化配置

当然,在项目中使用ObjectMapper时,有时候我们还需要做一些个性化配置,比如将Long和BigDemical类型的属性都通过字符串格式进行转换,防止前端使用时丢失数值精度。
这些类型转换的格式映射都可以在单例类中配置,代码如下:
@Getter
publicenum
 ObjectMapperInstance {


    INSTANCE;


privatefinal
 ObjectMapper objectMapper;


    ObjectMapperInstance() {

        objectMapper = 
new
 ObjectMapper();

// 注册自定义模块
        initialize();

    }


privatevoidinitialize()
{

        CustomJsonModule customJsonModule = 
new
 CustomJsonModule();

        objectMapper.registerModule(customJsonModule);

    }

}

在initialize()方法中给ObjectMapper注册自定义序列化转换器。
第一行是使用注册自定义序列换转换器后的效果,给id和price字段都加上了引号。
再来一次JMH测试:
可以看到,给ObjectMapper额外注册转换类型以后性能会受到一定的影响,但对业务影响不大。(啥业务能这么高的请求~)

小结

通过上面的测试,结论已经很清晰了。使用单例模式进行字符串转对象时性能可以提升18倍,而对象转String性能快了惊人的290万倍,所以在Spring中如何正确的使用ObjectMapper不用我再说了吧~

欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,长按”或“扫描”下方二维码噢
星球的内容包括:项目实战、面试招聘、源码解析、学习路线。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
继续阅读
阅读原文