Apache的BeanUtils、Spring的BeanUtils、Mapstruct、BeanCopier对象拷贝

博客地址:Apache的BeanUtils、Spring的BeanUtils、Mapstruct、BeanCopier对象拷贝

在项目中,尤其是在服务层,经常要将服务中的Dto实体对象拷贝到Entity对象用于前端展示。反过来也是一样,需要将前端请求对象转换为服务端的数据对象。现在市面上有很多这样的工具包,比如spring框架中就自带了BeanUtils,使我们进行这样的数据操作十分简单快捷。但是一直以来却没有关注到对象属性的拷贝性能问题,最近在想:单个对象的拷贝是快速的,可以不在意太多性能问题,可是如果数量级变大了会怎样呢?如果数量级到达了百万级别,会出现什么样的情况呢?

带着心中的疑问,我首先梳理出来现在有哪些对象拷贝的方式:

  1. Apache的BeanUtils:BeanUtils是Apache commens组件里面的成员,由Apache提供的一套开源api,用于简化对javaBean的操作,能够对基本类型自动转换。
  2. Spring的BeanUtils:BeanUtils是Spring框架提供的对Java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。
  3. Mapstruct:

MapStruct是一个Java 注释处理器,用于为Java Bean类生成类型安全和高性能的映射器。它使您不必手工编写映射代码,这是一个繁琐且容易出错的任务。该生成器具有合理的默认值和许多内置的类型转换,但是在配置或实现特殊行为时,它会自动退出。
与运行时工作的映射框架相比,MapStruct具有以下优点:

  • 通过使用普通方法调用而不是反射来快速执行
  • 编译时类型安全。只能映射彼此映射的对象和属性,因此不会将订单实体意外映射到客户DTO等。
  • 自包含代码 -没有运行时依赖项
  • 如果发生以下情况,则在构建时清除错误报告:
    • 映射不完整(并非所有目标属性都被映射)
    • 映射不正确(找不到正确的映射方法或类型转换)
  • 易于调试的映射代码(或手动编辑,例如在生成器中有错误的情况下)
    github mapstruct/mapstruct
  1. BeanCopier:BeanCopier是Cglib包中的一个类,用于对象的复制。目标对象必须先实例化 而且对象必须要有setter方法。

时间出真知,我使用的是相同的数据集,对每种方式都进行了测试。实体类如下:

@Data
public class UserVo {

    private String id;

    private String name;

    private Integer age;

    private String city;

    private String sex;

}

最终的测试结果如下:

数据量ApacheSpringMapStructBeanCopier
100w391ms250ms45ms57ms
10w82ms34ms8ms10ms
1w30ms19ms2ms7ms
1k15ms6ms1ms5ms
1005ms3ms1ms4ms
102ms1ms1ms4ms

根据测试结果,我们可以得出在速度方面,MapStruct是最好的,执行速度是 Apache BeanUtils 的10倍、Spring BeanUtils 的 4-5倍、和 BeanCopier 的速度差不多。
由此可以看出,在大数据量级的情况下,MapStruct 和 BeanCopier 都有着较高的性能优势,其中 MapStruct 尤为优秀。如果你仅是在日常处理少量的对象时,选取哪个其实变得并不重要,但数据量大时建议还是使用MapStruct 或 BeanCopier 的方式,提高接口性能。

当然,这个数据并没有考虑占用的内存和CPU的资源问题,仅仅是测试了在相同环境下的执行速度。


最后,如果你问我在日常选取哪种方式?我当然是选择使用 Spring 的 BeanUtils 了。虽然它的性能不是最优的,但是我日常也不会出现数十万级数据量的情况,Spring BeanUtils 对我来说完全够用了,同时在使用spring时不必再引入新的依赖包,何乐而不为不呢。所以来说,适用于自身场景的才是最好的,不必要过分追求性能。
但当有一天你遇到需要处理较大数据量级的对象时,请记得还有性能更加优秀的MapStruct 和 BeanCopier 供你选择。


青冥有晓月


版权声明:本文为Trend_H原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。