文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-11 17:44

关注

[[335679]]

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

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

Spring BeanUtils

Cglib BeanCopier

Apache BeanUtils

Apache PropertyUtils

Dozer

由于篇幅优先,关于这几种工具类的用法及区别,还有到底是什么是浅拷贝和深拷贝不在本文的讨论范围内。本文主要聚焦于对比这几个类库的性能问题。

性能对比

No Data No BB,我们就来写代码来对比下这几种框架的性能情况。代码示例如下:首先定义一个PersonDO类:

  1. public class PersonDO { 
  2.  
  3.     private Integer id; 
  4.  
  5.     private String name
  6.  
  7.     private Integer age; 
  8.  
  9.     private Date birthday; 
  10.  
  11.     //省略setter/getter 
  12.  

再定义一个PersonDTO类:

  1. public class PersonDTO { 
  2.  
  3.     private String name
  4.  
  5.     private Integer age; 
  6.  
  7.     private Date birthday; 
  8.  

然后进行测试类的编写:使用Spring BeanUtils进行属性拷贝:

  1. private void mappingBySpringBeanUtils(PersonDO personDO, int times) { 
  2.  
  3.     StopWatch stopwatch = new StopWatch(); 
  4.  
  5.     stopwatch.start(); 
  6.  
  7.  
  8.     for (int i = 0; i < times; i++) { 
  9.  
  10.         PersonDTO personDTO = new PersonDTO(); 
  11.  
  12.         org.springframework.beans.BeanUtils.copyProperties(personDO, personDTO); 
  13.  
  14.     } 
  15.  
  16.     stopwatch.stop(); 
  17.  
  18.     System.out.println("mappingBySpringBeanUtils cost :" + stopwatch.getTotalTimeMillis()); 
  19.  

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

使用Cglib BeanCopier进行属性拷贝:

  1. private void mappingByCglibBeanCopier(PersonDO personDO, int times) { 
  2.  
  3.     StopWatch stopwatch = new StopWatch(); 
  4.  
  5.     stopwatch.start(); 
  6.  
  7.     for (int i = 0; i < times; i++) { 
  8.  
  9.         PersonDTO personDTO = new PersonDTO(); 
  10.  
  11.         BeanCopier copier = BeanCopier.create(PersonDO.class, PersonDTO.class, false); 
  12.  
  13.         copier.copy(personDO, personDTO, null); 
  14.  
  15.     } 
  16.  
  17.     stopwatch.stop(); 
  18.  
  19.     System.out.println("mappingByCglibBeanCopier cost :" + stopwatch.getTotalTimeMillis()); 
  20.  

使用Apache BeanUtils进行属性拷贝:

  1. private void mappingByApacheBeanUtils(PersonDO personDO, int times) 
  2.  
  3.     throws InvocationTargetException, IllegalAccessException { 
  4.  
  5.     StopWatch stopwatch = new StopWatch(); 
  6.  
  7.     stopwatch.start(); 
  8.  
  9.     for (int i = 0; i < times; i++) { 
  10.  
  11.         PersonDTO personDTO = new PersonDTO(); 
  12.  
  13.         BeanUtils.copyProperties(personDTO, personDO); 
  14.  
  15.     } 
  16.  
  17.     stopwatch.stop(); 
  18.  
  19.     System.out.println("mappingByApacheBeanUtils cost :" + stopwatch.getTotalTimeMillis()); 
  20.  

使用Apache PropertyUtils进行属性拷贝:

  1. private void mappingByApachePropertyUtils(PersonDO personDO, int times) 
  2.  
  3.     throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { 
  4.  
  5.     StopWatch stopwatch = new StopWatch(); 
  6.  
  7.     stopwatch.start(); 
  8.  
  9.     for (int i = 0; i < times; i++) { 
  10.  
  11.         PersonDTO personDTO = new PersonDTO(); 
  12.  
  13.         PropertyUtils.copyProperties(personDTO, personDO); 
  14.  
  15.     } 
  16.  
  17.     stopwatch.stop(); 
  18.  
  19.     System.out.println("mappingByApachePropertyUtils cost :" + stopwatch.getTotalTimeMillis()); 
  20.  

然后执行以下代码:

  1. public static void main(String[] args) 
  2.  
  3.     throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { 
  4.  
  5.     PersonDO personDO = new PersonDO(); 
  6.  
  7.     personDO.setName("Hollis"); 
  8.  
  9.     personDO.setAge(26); 
  10.  
  11.     personDO.setBirthday(new Date()); 
  12.  
  13.     personDO.setId(1); 
  14.  
  15.  
  16.     MapperTest mapperTest = new MapperTest(); 
  17.  
  18.  
  19.     mapperTest.mappingBySpringBeanUtils(personDO, 100); 
  20.  
  21.     mapperTest.mappingBySpringBeanUtils(personDO, 1000); 
  22.  
  23.     mapperTest.mappingBySpringBeanUtils(personDO, 10000); 
  24.  
  25.     mapperTest.mappingBySpringBeanUtils(personDO, 100000); 
  26.  
  27.     mapperTest.mappingBySpringBeanUtils(personDO, 1000000); 
  28.  
  29.     mapperTest.mappingByCglibBeanCopier(personDO, 100); 
  30.  
  31.     mapperTest.mappingByCglibBeanCopier(personDO, 1000); 
  32.  
  33.     mapperTest.mappingByCglibBeanCopier(personDO, 10000); 
  34.  
  35.     mapperTest.mappingByCglibBeanCopier(personDO, 100000); 
  36.  
  37.     mapperTest.mappingByCglibBeanCopier(personDO, 1000000); 
  38.  
  39.     mapperTest.mappingByApachePropertyUtils(personDO, 100); 
  40.  
  41.     mapperTest.mappingByApachePropertyUtils(personDO, 1000); 
  42.  
  43.     mapperTest.mappingByApachePropertyUtils(personDO, 10000); 
  44.  
  45.     mapperTest.mappingByApachePropertyUtils(personDO, 100000); 
  46.  
  47.     mapperTest.mappingByApachePropertyUtils(personDO, 1000000); 
  48.  
  49.     mapperTest.mappingByApacheBeanUtils(personDO, 100); 
  50.  
  51.     mapperTest.mappingByApacheBeanUtils(personDO, 1000); 
  52.  
  53.     mapperTest.mappingByApacheBeanUtils(personDO, 10000); 
  54.  
  55.     mapperTest.mappingByApacheBeanUtils(personDO, 100000); 
  56.  
  57.     mapperTest.mappingByApacheBeanUtils(personDO, 1000000); 
  58.  

得到结果如下:

工具类 执行1000次耗时 执行10000次耗时 执行100000次耗时 执行1000000次耗时
Spring BeanUtils 5ms 10ms 45ms 169ms
Cglib BeanCopier 4ms 18ms 45ms 91ms
Apache PropertyUtils 60ms 265ms 1444ms 11492ms
Apache BeanUtils 138ms 816ms 4154ms 36938ms
Dozer 566ms 2254ms 11136ms 102965ms

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

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

所以,如果考虑性能情况的话,建议大家不要选择Apache PropertyUtils、Apache BeanUtils以及Dozer等工具类。很多人会不理解,为什么大名鼎鼎的Apache开源出来的的类库性能确不高呢?这不像是Apache的风格呀,这背后导致性能低下的原因又是什么呢?其实,是因为Apache BeanUtils力求做得完美, 在代码中增加了非常多的校验、兼容、日志打印等代码,过度的包装导致性能下降严重。

总结

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

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

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

 

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

  1. --Apache PropertyUtils、Apache BeanUtils--> 
  2.  
  3.  
  4.  
  5.     commons-beanutils 
  6.  
  7.     commons-beanutils 
  8.  
  9.     1.9.4 
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.     commons-logging 
  18.  
  19.     commons-logging 
  20.  
  21.     1.1.2 
  22.  
  23.  
  24.  
  25.  
  26.  
  27. --Spring PropertyUtils--> 
  28.  
  29.  
  30.  
  31.     org.springframework 
  32.  
  33.     org.springframework.beans 
  34.  
  35.     3.1.1.RELEASE 
  36.  
  37.  
  38.  
  39.  
  40.  
  41. --cglib--> 
  42.  
  43.  
  44.  
  45.     cglib 
  46.  
  47.     cglib-nodep 
  48.  
  49.     2.2.2 
  50.  
  51.  
  52.  
  53.  
  54.  
  55. --dozer--> 
  56.  
  57.  
  58.  
  59.     net.sf.dozer 
  60.  
  61.     dozer 
  62.  
  63.     5.5.1 
  64.  
  65.  
  66.  
  67.  
  68.  
  69. --日志相关--> 
  70.  
  71.  
  72.  
  73.     org.slf4j 
  74.  
  75.     slf4j-api 
  76.  
  77.     1.7.7 
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.     org.slf4j 
  86.  
  87.     jul-to-slf4j 
  88.  
  89.     1.7.7 
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.     org.slf4j 
  98.  
  99.     jcl-over-slf4j 
  100.  
  101.     1.7.7 
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.     org.slf4j 
  110.  
  111.     log4j-over-slf4j 
  112.  
  113.     1.7.7 
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.     org.slf4j 
  122.  
  123.     slf4j-jdk14 
  124.  
  125.     1.7.7 
  126.  
  127.  

 

来源:51CTO专栏内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯