为什么阿里巴巴禁止使用Apache BeanUtils进行属性值Copy

简介: 为什么阿里巴巴禁止使用Apache BeanUtils进行属性值Copy

前言

在日常开发中,不可避免的遇到对象属性相同的情况,为了方便,不通过setter,进行一个个的字段赋值,而是通过BeanUtils进行copy。快速的实现了,对象属性值得copy、赋值。

因此,各种技术框架都实现了自己的BeanUtils。比较知名的,包括:

1、Spring BeanUtils 2、Cglib BeanCopier 3、Apache BeanUtils 4、Apache PropertyUtils 5、Dozer

那么,到底哪个更优秀,没有bug,值得我们推广使用呢?先放着这个问题在心里,众所周知,阿里的开发者手册,愈来愈成为一种开发行为规范,被业内广泛认可。目前,已经是经过了好几个版本的更新。目前是嵩山版,有需要的,可以到阿里云开发者社区,下载。官网链接: https://developer.aliyun.com

在开发者手册中,提到了以下内容

image.png

那么,到底是为什么把Apache Beanutils给pass了呢?带着上述两个问题,开启我们今天学习的征程。

性能对比

我们将对上述几种属性copy方式,分别测试,统计耗时,对比其各中性能。

测试对象创建。创建属性相同的两个实体类。

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

往往存在,接口传输对象与数据库存储实体对象之间,有上述类似关系。

开始测试,编写测试方法类

public class CopyTest {
// 使用Spring BeanUtils进行属性拷贝
   public static void copyBySpringBeanUtils(PersonDto personDto, int times) {
       long start = System.currentTimeMillis();
       for (int i = 0; i < times; i++) {
           PersonEntity personEntity = new PersonEntity();
           org.springframework.beans.BeanUtils.copyProperties(personDto, personEntity);
      }
       long end = System.currentTimeMillis();
       System.out.println("SpringBeanUtils复制次数:" + times + " ,耗时:" + (end - start) + "ms");
  }
// 使用CglibBeanCopier进行属性拷贝:
   public static void copyByCglibBeanCopier(PersonDto personDto, int times) {
       long start = System.currentTimeMillis();
       for (int i = 0; i < times; i++) {
           PersonEntity personEntity = new PersonEntity();
           BeanCopier copier = BeanCopier.create(PersonDto.class, PersonEntity.class, false);
           copier.copy(personDto, personEntity, null);
      }
       long end = System.currentTimeMillis();
       System.out.println("CglibBeanCopier复制次数:" + times + " ,耗时:" + (end - start) + "ms");
  }
// 使用ApacheBeanUtils进行属性拷贝:
   public static void copyByApacheBeanUtils(PersonDto personDto, int times) throws InvocationTargetException, IllegalAccessException {
       long start = System.currentTimeMillis();
       for (int i = 0; i < times; i++) {
           PersonEntity personEntity = new PersonEntity();
           BeanUtils.copyProperties(personDto, personEntity);
      }
       long end = System.currentTimeMillis();
       System.out.println("ApacheBeanUtils复制次数:" + times + " ,耗时:" + (end - start) + "ms");
  }
// 使用ApachePropertyUtils进行属性拷贝:
   public static void copyByApachePropertyUtils(PersonDto personDto, int times) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
       long start = System.currentTimeMillis();
       for (int i = 0; i < times; i++) {
           PersonEntity personEntity = new PersonEntity();
           PropertyUtils.copyProperties(personDto, personEntity);
      }
       long end = System.currentTimeMillis();
       System.out.println("ApachePropertyUtils复制次数:" + times + " ,耗时:" + (end - start) + "ms");
  }
}

编写执行类

public class CopyTestExec {
   public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
       PersonDto personDto = new PersonDto();
       personDto.setId(1);
       personDto.setName("小隐乐乐");
       personDto.setAge(18);
       personDto.setBirthday(new Date());
       CopyTest.copyBySpringBeanUtils(personDto, 100);
       CopyTest.copyBySpringBeanUtils(personDto, 1000);
       CopyTest.copyBySpringBeanUtils(personDto, 10000);
       CopyTest.copyBySpringBeanUtils(personDto, 100000);
       CopyTest.copyBySpringBeanUtils(personDto, 1000000);
       CopyTest.copyByCglibBeanCopier(personDto, 100);
       CopyTest.copyByCglibBeanCopier(personDto, 1000);
       CopyTest.copyByCglibBeanCopier(personDto, 10000);
       CopyTest.copyByCglibBeanCopier(personDto, 100000);
       CopyTest.copyByCglibBeanCopier(personDto, 1000000);
       CopyTest.copyByApacheBeanUtils(personDto, 100);
       CopyTest.copyByApacheBeanUtils(personDto, 1000);
       CopyTest.copyByApacheBeanUtils(personDto, 10000);
       CopyTest.copyByApacheBeanUtils(personDto, 100000);
       CopyTest.copyByApacheBeanUtils(personDto, 1000000);
       CopyTest.copyByApachePropertyUtils(personDto, 100);
       CopyTest.copyByApachePropertyUtils(personDto, 1000);
       CopyTest.copyByApachePropertyUtils(personDto, 10000);
       CopyTest.copyByApachePropertyUtils(personDto, 100000);
       CopyTest.copyByApachePropertyUtils(personDto, 1000000);
  }
}

执行结果如下:

SpringBeanUtils   复制次数:100     ,耗时:120ms
SpringBeanUtils   复制次数:1000   ,耗时:8ms
SpringBeanUtils   复制次数:10000   ,耗时:20ms
SpringBeanUtils   复制次数:100000 ,耗时:57ms
SpringBeanUtils   复制次数:1000000 ,耗时:242ms
CglibBeanCopier   复制次数:100     ,耗时:82ms
CglibBeanCopier   复制次数:1000   ,耗时:9ms
CglibBeanCopier   复制次数:10000   ,耗时:20ms
CglibBeanCopier   复制次数:100000 ,耗时:64ms
CglibBeanCopier   复制次数:1000000 ,耗时:102ms
ApacheBeanUtils   复制次数:100     ,耗时:60ms
ApacheBeanUtils   复制次数:1000   ,耗时:29ms
ApacheBeanUtils   复制次数:10000   ,耗时:62ms
ApacheBeanUtils   复制次数:100000 ,耗时:243ms
ApacheBeanUtils   复制次数:1000000 ,耗时:2282ms
ApachePropertyUtils复制次数:100     ,耗时:0ms
ApachePropertyUtils复制次数:1000   ,耗时:2ms
ApachePropertyUtils复制次数:10000   ,耗时:21ms
ApachePropertyUtils复制次数:100000 ,耗时:190ms
ApachePropertyUtils复制次数:1000000 ,耗时:1941ms

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

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

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

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

依赖

 

<dependencies>
       <!--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.2.2.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>
   </dependencies>


总结

通过本文测试,回答了前言中两个问题,明确了为何开发者手册中的强调,不使用Apache BeanUtils

目录
相关文章
|
8月前
|
Java Apache Spring
Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求
【5月更文挑战第4天】Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求;Cglib BeanCopier用于转换为Cglib代理对象;Apache PropertyUtils处理属性操作;Dozer支持复杂对象映射。选择工具取决于具体需求,如需精细控制或对象映射,推荐Dozer或Apache PropertyUtils。Apache BeanUtils可能因潜在的封装性破坏被禁用。
79 3
|
Java Apache Spring
Spring BeanUtils 2、Cglib BeanCopier 3、Apache BeanUtils 4、Apache PropertyUtils 5、Dozer 那么,我们到底应该选择哪种工具类更加合适呢?为什么Java开发手册中提到禁止使用Apache BeanUtils呢
Spring BeanUtils 2、Cglib BeanCopier 3、Apache BeanUtils 4、Apache PropertyUtils 5、Dozer 那么,我们到底应该选择哪种工具类更加合适呢?为什么Java开发手册中提到禁止使用Apache BeanUtils呢
109 0
|
Java Apache Maven
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
我们到底应该选择哪种属性拷贝类工具更加合适呢?为什么阿里巴巴Java开发手册中提到禁止使用Apache BeanUtils呢?
12410 0
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
|
SQL 存储 资源调度
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
214 0
|
大数据 Apache 流计算
阿里巴巴编程之夏项目——Apache Flink
项目介绍: Apache Flink 是由 Apache 软件基金会开发的开源流处理框架,其核心是用 Java 和 Scala 编写的分布式流数据流引擎。Flink 以数据并行和流水线方式执行任意流数据程序,Flink 的流水线运行时系统可以执行批处理和流处理程序。
4350 0
|
SQL 大数据 API
阿里巴巴为什么选择Apache Flink?
作者:王峰 整理:韩非 本文主要整理自云栖大会阿里巴巴计算平台事业部资深技术专家王峰(花名:莫问)在云栖大会‘开发者生态峰会’上发表的演讲。 伴随着海量增长的数据,数字化时代的未来感扑面而至。
1736 0
|
22天前
|
存储 人工智能 大数据
The Past, Present and Future of Apache Flink
本文整理自阿里云开源大数据负责人王峰(莫问)在 Flink Forward Asia 2024 上海站主论坛开场的分享,今年正值 Flink 开源项目诞生的第 10 周年,借此时机,王峰回顾了 Flink 在过去 10 年的发展历程以及 Flink社区当前最新的技术成果,最后展望下一个十年 Flink 路向何方。
312 33
The Past, Present and Future of Apache Flink
|
3月前
|
SQL Java API
Apache Flink 2.0-preview released
Apache Flink 社区正积极筹备 Flink 2.0 的发布,这是自 Flink 1.0 发布以来的首个重大更新。Flink 2.0 将引入多项激动人心的功能和改进,包括存算分离状态管理、物化表、批作业自适应执行等,同时也包含了一些不兼容的变更。目前提供的预览版旨在让用户提前尝试新功能并收集反馈,但不建议在生产环境中使用。
882 13
Apache Flink 2.0-preview released
|
3月前
|
存储 缓存 算法
分布式锁服务深度解析:以Apache Flink的Checkpointing机制为例
【10月更文挑战第7天】在分布式系统中,多个进程或节点可能需要同时访问和操作共享资源。为了确保数据的一致性和系统的稳定性,我们需要一种机制来协调这些进程或节点的访问,避免并发冲突和竞态条件。分布式锁服务正是为此而生的一种解决方案。它通过在网络环境中实现锁机制,确保同一时间只有一个进程或节点能够访问和操作共享资源。
111 3
|
4月前
|
SQL 消息中间件 关系型数据库
Apache Doris Flink Connector 24.0.0 版本正式发布
该版本新增了对 Flink 1.20 的支持,并支持通过 Arrow Flight SQL 高速读取 Doris 中数据。

推荐镜像

更多