暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

BeanUtils.copyProperties知多少?

小王博客基地 2023-01-12
370

为了丰富公众号文章,特意引进大佬的文章,感兴趣可以去大佬csdn看看文章:

https://blog.csdn.net/weixin_42313773?type=blog


事出有因

近期在读《阿里巴巴开发手册》的时候发现:阿里强制避免使用BeanUtils进行属性的拷贝,但是不得不承认的是,在我自己的项目中确实使用过Apache的Beanutils进行属性拷贝,在读了开发手册后,感觉项目中的代码可以优化一下,基于不同包下的BeanUtils性能和特性有所不同,当然用法也不尽相同,所以,可以你可能会跳入因为导错包导致对象拷贝为null的坑。

浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。(类似a对象的指针指到了b)

深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

比物连类

目前已有其他大佬对Apache、Spring的工具类进行了数据对比:详细请看:

几种copyProperties工具类性能比较:https://www.jianshu.com/p/bcbacab3b89e

借用大佬的数据说明下结果:

工具名称执行1000次耗时10000次100000次1000000次
Apache BeanUtils390ms854ms1763ms8408ms
Apache PropertyUtils26ms221ms352ms2663ms
spring BeanUtils39ms315ms373ms949ms
Cglib BeanCopier64ms144ms171ms309ms

Apache的BeanUtils去拷贝属性时,性能是最慢的,数据拷贝皆使用Java的反射实现,Apache比较慢的原因是:

  • 进行大量参数校验

  • 使用解析类型转换

Apache源码
Apache源码

spring中的BeanUtils去拷贝属性时就是对两个对象中相同名字的属性进行简单get/set,仅检查属性的可访问性。实现的方式没有太复杂的逻辑,代码执行较快。

物尽其用

在使用BeanUtils时,会先引用对应的包,如果包引用不对的话,就可能会跳入开头的大坑中,具体如下:

org.apache.commons.beanutils.BeanUtils

BeanUtils.copyProperties(a,b);
b的值赋值a

复制

org.springframework.beans.BeanUtils

BeanUtils.copyProperties(a,b);
a的值赋给b

复制

归根结蒂

正如上文的测试数据,如果不是阿里级别的并发量、数据量,其实三种工具类的性能差距是感知力不强的,倒不如去优化SQL对性能来的实在,但是既然有了更好的选择,仅仅是导入不同的包,参数位置的不同而已,如果属性值比较少,没必要使用属性拷贝,直接手动get/set即可。所以,代码中我们尽量使用性能较高且可行的方案。重要的是对于代码的责任心和负责度,正如雷军先生说过的那样:我们要像写诗一样写代码,尽量使代码更加优雅。所以,我推荐MapStruct

ps:请MapStruct把我的广告费结一下

复制

别开生面

分布式项目中,不同的应用与应用之间,还有单独的应用细分模块之后,DO 一般不会让外部依赖,这时候需要在提供对外接口的模块里放 DTO 用于对象传输,也即是 DO 对象对内,DTO对象对外,DTO 可以根据业务需要变更,并不需要映射 DO 的全部属性。这种 对象与对象之间的互相转换,就需要有一个专门用来解决转换问题的工具,毕竟每一个字段都 get/set 会很麻烦。我在跟前阿里员工合作的时候,属性转换使用的是MapStruct,只需要定义一个 Mapper 接口,MapStruct 就会自动实现这个映射接口,避免了复杂繁琐的映射实现。


文章转载自小王博客基地,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论