阿里巴巴为什么禁止使用Apache Beanutils进行属性复制?

作者 l Hollis

来源 l Hollis(ID:hollischuang)

在日常开发中,我们经常需要给对象进行赋值,通常会调用其set/get方法,有些时候,如果我们要转换的两个对象之间属性大致相同,会考虑使用属性拷贝工具进行。

如我们经常在代码中会对一个数据结构封装成DO、SDO、DTO、VO等,而这些Bean中的大部分属性都是一样的,所以使用属性拷贝类工具可以帮助我们节省大量的set和get操作。

市面上有很多类似的工具类,比较常用的有

1、Spring BeanUtils 

2、Cglib BeanCopier 

3、Apache BeanUtils 

4、Apache PropertyUtils 

5、Dozer

那么,我们到底应该选择哪种工具类更加合适呢?为什么阿里巴巴Java开发手册中提到禁止使用Apache BeanUtils呢?

由于篇幅优先,关于这几种工具类的用法及区别,还有到底是什么是浅拷贝和深拷贝不在本文的讨论范围内。

本文主要聚焦于对比这几个类库的性能问题。

性能对比

No Data No BB,我们就来写代码来对比下这几种框架的性能情况。

代码示例如下:

首先定义一个PersonDO类:

public class PersonDO {private Integer id;private String name;private Integer age;private Date birthday;//省略setter/getter}

再定义一个PersonDTO类:

public class PersonDTO {private String name;private Integer age;private Date birthday;}

然后进行测试类的编写:

使用Spring BeanUtils进行属性拷贝:

private void mappingBySpringBeanUtils(PersonDO personDO, int times) {StopWatch stopwatch = new StopWatch();stopwatch.start();for (int i = 0; i < times; i++) {PersonDTO personDTO = new PersonDTO();org.springframework.beans.BeanUtils.copyProperties(personDO, personDTO);}stopwatch.stop();System.out.println("mappingBySpringBeanUtils cost :" + stopwatch.getTotalTimeMillis());}

其中的StopWatch用于记录代码执行时间,方便进行对比。

使用Cglib BeanCopier进行属性拷贝:

private void mappingByCglibBeanCopier(PersonDO personDO, int times) {StopWatch stopwatch = new StopWatch();stopwatch.start();for (int i = 0; i < times; i++) {PersonDTO personDTO = new PersonDTO();BeanCopier copier = BeanCopier.create(PersonDO.class, PersonDTO.class, false);copier.copy(personDO, personDTO, null);}stopwatch.stop();System.out.println("mappingByCglibBeanCopier cost :" + stopwatch.getTotalTimeMillis());}

使用Apache BeanUtils进行属性拷贝:

private void mappingByApacheBeanUtils(PersonDO personDO, int times)throws InvocationTargetException, IllegalAccessException {StopWatch stopwatch = new StopWatch();stopwatch.start();for (int i = 0; i < times; i++) {PersonDTO personDTO = new PersonDTO();BeanUtils.copyProperties(personDTO, personDO);}stopwatch.stop();System.out.println("mappingByApacheBeanUtils cost :" + stopwatch.getTotalTimeMillis());}

使用Apache PropertyUtils进行属性拷贝:

private void mappingByApachePropertyUtils(PersonDO personDO, int times)throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {StopWatch stopwatch = new StopWatch();stopwatch.start();for (int i = 0; i < times; i++) {PersonDTO personDTO = new PersonDTO();PropertyUtils.copyProperties(personDTO, personDO);}stopwatch.stop();System.out.println("mappingByApachePropertyUtils cost :" + stopwatch.getTotalTimeMillis());}

然后执行以下代码:

public static void main(String[] args)throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {PersonDO personDO = new PersonDO();personDO.setName("Hollis");personDO.setAge(26);personDO.setBirthday(new Date());personDO.setId(1);MapperTest mapperTest = new MapperTest();mapperTest.mappingBySpringBeanUtils(personDO, 100);mapperTest.mappingBySpringBeanUtils(personDO, 1000);mapperTest.mappingBySpringBeanUtils(personDO, 10000);mapperTest.mappingBySpringBeanUtils(personDO, 100000);mapperTest.mappingBySpringBeanUtils(personDO, 1000000);mapperTest.mappingByCglibBeanCopier(personDO, 100);mapperTest.mappingByCglibBeanCopier(personDO, 1000);mapperTest.mappingByCglibBeanCopier(personDO, 10000);mapperTest.mappingByCglibBeanCopier(personDO, 100000);mapperTest.mappingByCglibBeanCopier(personDO, 1000000);mapperTest.mappingByApachePropertyUtils(personDO, 100);mapperTest.mappingByApachePropertyUtils(personDO, 1000);mapperTest.mappingByApachePropertyUtils(personDO, 10000);mapperTest.mappingByApachePropertyUtils(personDO, 100000);mapperTest.mappingByApachePropertyUtils(personDO, 1000000);mapperTest.mappingByApacheBeanUtils(personDO, 100);mapperTest.mappingByApacheBeanUtils(personDO, 1000);mapperTest.mappingByApacheBeanUtils(personDO, 10000);mapperTest.mappingByApacheBeanUtils(personDO, 100000);mapperTest.mappingByApacheBeanUtils(personDO, 1000000);}

得到结果如下:

工具类执行1000次耗时执行10000次耗时执行100000次耗时执行1000000次耗时
Spring BeanUtils5ms10ms45ms169ms
Cglib BeanCopier4ms18ms45ms91ms
Apache PropertyUtils60ms265ms1444ms11492ms
Apache BeanUtils138ms816ms4154ms36938ms
Dozer566ms2254ms11136ms102965ms

画了一张折线图更方便大家进行对比

综上,我们基本可以得出结论,在性能方面,Spring BeanUtils和Cglib BeanCopier表现比较不错,而Apache PropertyUtils、Apache BeanUtils以及Dozer则表现的很不好。

所以,如果考虑性能情况的话,建议大家不要选择Apache PropertyUtils、Apache BeanUtils以及Dozer等工具类。

很多人会不理解,为什么大名鼎鼎的Apache开源出来的的类库性能确不高呢?这不像是Apache的风格呀,这背后导致性能低下的原因又是什么呢?

其实,是因为Apache BeanUtils力求做得完美, 在代码中增加了非常多的校验、兼容、日志打印等代码,过度的包装导致性能下降严重。

总结

本文通过对比几种常见的属性拷贝的类库,分析得出了这些工具类的性能情况,最终也验证了《阿里巴巴Java开发手册》中提到的"Apache BeanUtils 效率低"的事实。

但是本文只是站在性能这一单一角度进行了对比,我们在选择一个工具类的时候还会有其他方面的考虑,比如使用成本、理解难度、兼容性、可扩展性等,对于这种拷贝类工具类,我们还会考虑其功能是否完善等。

就像虽然Dozer性能比较差,但是他可以很好的和Spring结合,可以通过配置文件等进行属性之间的映射等,也受到了很多开发者的喜爱。

本文用到的第三方类库的maven依赖如下:

<!--Apache PropertyUtils、Apache BeanUtils--><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1.2</version></dependency><!--Spring PropertyUtils--><dependency><groupId>org.springframework</groupId><artifactId>org.springframework.beans</artifactId><version>3.1.1.RELEASE</version></dependency><!--cglib--><dependency><groupId>cglib</groupId><artifactId>cglib-nodep</artifactId><version>2.2.2</version></dependency><!--dozer--><dependency><groupId>net.sf.dozer</groupId><artifactId>dozer</artifactId><version>5.5.1</version></dependency><!--日志相关--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.7</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jul-to-slf4j</artifactId><version>1.7.7</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.7</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>1.7.7</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-jdk14</artifactId><version>1.7.7</version></dependency>


往期推荐

URL 去重的 6 种方案!(附详细代码)


多图证明,Java到底是值传递还是引用传递?


阿里为什么推荐使用LongAdder,而不是volatile?

关注下方二维码,收获更多干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

台达A2-M伺服

地址: P3.00 从站地址0x01~0x7F【1~127】 P3.01 通讯速度UZYX【0403】 X:0【4800】1【9600】2【19200】3【38400】4【57600】5【115200】Z:0【125Kbit/s】1【250】2【500】3【750】4【1Mbit/s】 P3.02 通讯格式6【8N2】7【8E1】8【8O1】 P3.03 1通讯错误刹停…

关于数组首地址a、a+1、a[0]、a[0]+1、*a、*a、a+0的解析

有一个数组&#xff1a; int a[4]{1,2,3,4};例如&#xff0c;sizeof(a),很明显它的结果是16&#xff0c;这个a就表示的是整个数组的大小&#xff0c;那么有 a1: 表示数组a的第二个元素即a[1]的地址 a0&#xff1a; a[0]的地址 &a[0]: a[0]的地址 &a[0…

Intent, Bundle, ListView的简单使用

Intent, Bundle, ListView的使用 无参数的Activity跳转&#xff1a; intent.setClass(MainActivity.this, InformationActivity.class); startActivity(intent);当前Activity A 向下一个Activity B跳转并传递数据&#xff1a; Bundle bundle new Bundle(); bundle.putString(…

vb随机显示图片

根目录下建一个文件夹PIC&#xff0c;在PIC下存放5张图片&#xff0c;名称分虽是1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5然后添加一个timer1控件&#xff0c;一个image1控件&#xff0c;它的interval设5000&#xff08;即5秒&#xff09;写如下代码Private Sub…

正则数字字母下划线至少两种_8085微处理器中至少两个8位数字

正则数字字母下划线至少两种Problem statement: 问题陈述&#xff1a; To find minimum of two 8bit numberusing 8085 microprocessor. 使用8085微处理器查找最少两个8位数字。 Algorithm: 算法&#xff1a; Load the accumulator with the first data. 向累加器加载第一个…

字符串操作的12个小技巧!

字符串可以说是 Java 中最具有代表性的类了&#xff0c;似乎没有之一哈&#xff0c;这就好像直播界的李佳琪&#xff0c;脱口秀中的李诞&#xff0c;一等一的大哥地位。不得不承认&#xff0c;最近吐槽大会刷多了&#xff0c;脑子里全是那些段子&#xff0c;写文章都有点不由自…

关于二维数组取地址加以或减一解引用问题

int main() { int aa[2][5] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int *ptr1 (int *)(&aa 1); int *ptr2 (int *)(*(aa 1)); printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));system("pause");return 0; }很显然aa是一个二维数组&#xff0c;很多…

rand和srand的用法

首先我们要对rand&#xff06;srand有个总体的看法:srand初始化随机种子,rand产生随机数&#xff0c;下面将详细说明。rand&#xff08;产生随机数&#xff09;表头文件: #include定义函数 :int rand(void)函数说明 :因为rand的内部实现是用线性同余法做的&#xff0c;他不是真…

repeating 路由_CSS中带有示例的repeating-linear-gradient()函数

repeating 路由Introduction: 介绍&#xff1a; So far, we have learned so many functions but learning never gets enough, therefore as a good developer, we must learn as many functions as we can and know their behavior with the help of practical implementati…

万字详解|手撕 9大排序算法!

0. 前言大家好&#xff0c;我是多选参数的程序锅&#xff0c;一个正在捣鼓操作系统、学数据结构和算法以及 Java 的失业人员。数据结构和算法我已经学了有一段日子了&#xff0c;最近也开始在刷 LeetCode 上面的题目了&#xff0c;但是自己感觉在算法上还是 0 &#xff0c;还得…

INF文件修改注册表

INF是一个用于安装驱动程序的文件&#xff0c;是文本格式的。里面记录着驱动程序的所有相关资料&#xff0c;随便打开一个INF文件度可看到很多奇奇怪怪的东西&#xff0c;其实这一点也不奇怪&#xff0c;因为每一项都有特定的含义&#xff0c;比如从VERSION一项就可以看出支持的…

.Net判断一个对象是否为数值类型探讨总结(高营养含量,含最终代码及跑分)...

前一篇发出来后引发了积极的探讨&#xff0c;起到了抛砖引玉效果&#xff0c;感谢大家参与。 吐槽一下&#xff1a;这个问题比其看起来要难得多得多啊。 大家的讨论最终还是没有一个完全正确的答案&#xff0c;不过我根据讨论结果总结了一个差不多算是最终版的代码&#xff0c;…

ai怎么约束每个字的大小_人工智能的约束满意问题

ai怎么约束每个字的大小Constraint Satisfactory problems, as the name suggests are the problems which have some constraints which need to be satisfied while solving any problem. In simpler words, we can say that while solving any problem or changing any stat…

一个多月的时间,终于把这件事做完了!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;关注我的小伙伴都知道&#xff0c;前段时间磊哥搞了一个免费的模拟面试&#xff0c;但因为工作和&#xff08;面试&#xff…

简易电子密码锁制作

看到电影里面的保险箱用到的密码锁&#xff0c;于是心血来潮动手做了一个简单的密码锁&#xff0c;其有3次输入的机会&#xff0c;全错的话便进入死循环&#xff0c;一直警报&#xff0c;任何操作都无效&#xff0c;除了复位操作哈。所需素材&#xff1a;51单片机、1602液晶、蜂…

漫画:什么是红黑树?(整合版)

前段时间&#xff0c;小灰发布了红黑树相关的文章&#xff0c;分成上下篇来讲解。这一次&#xff0c;小灰把两篇文章做了整合&#xff0c;并且修正了红黑树删除部分的图片错误&#xff0c;感谢大家的指正。————— 第二天 —————————————————二叉查找树&a…

PHP高并发高负载系统架构

2019独角兽企业重金招聘Python工程师标准>>> 一、高并发和高负载的约束条件 硬件部署操作系统Web 服务器PHPMySQL测试二、解决之道——硬件篇 处理能力的提升&#xff1a;部署多颗CPU&#xff0c;选择多核心、具备更高运算频率、更大高速缓存的CPU&#xff1b; 处理…

Java ObjectInputStream registerValidation()方法与示例

ObjectInputStream类registerValidation()方法 (ObjectInputStream Class registerValidation() method) registerValidation() method is available in java.io package. registerValidation()方法在java.io包中可用。 registerValidation() method is used to register an ob…

电脑系统越来越慢,怎么删除临时文件

1.关闭"休眠"方法:打开[控制面板]→[电源选项]→[休眠],把"启用休眠"前面的勾去掉说明:休眠是系统长时间一种待机状态,使您在长时间离开电脑时保存操作状态,如果您不是经常开着电脑到别处去的话,那就把它关了吧!☆立即节省:256M2.关闭"系统还原"…

线性方程组的矩阵表示_用矩阵表示线性方程组

线性方程组的矩阵表示A Linear Equation can be represented in matrix form using a: 线性方程可以使用以下形式以矩阵形式表示 &#xff1a; Coefficient Matrix 系数矩阵 Variable Matrix and 可变矩阵和 Constant Matrix 常数矩阵 The System of linear equation in three…