为什么阿里巴巴禁止使用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

目录
相关文章
|
4月前
|
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呢
61 0
|
SQL 存储 资源调度
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
171 0
|
Java Apache Maven
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
我们到底应该选择哪种属性拷贝类工具更加合适呢?为什么阿里巴巴Java开发手册中提到禁止使用Apache BeanUtils呢?
12215 0
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
|
大数据 Apache 流计算
阿里巴巴编程之夏项目——Apache Flink
项目介绍: Apache Flink 是由 Apache 软件基金会开发的开源流处理框架,其核心是用 Java 和 Scala 编写的分布式流数据流引擎。Flink 以数据并行和流水线方式执行任意流数据程序,Flink 的流水线运行时系统可以执行批处理和流处理程序。
4217 0
|
SQL 大数据 API
阿里巴巴为什么选择Apache Flink?
作者:王峰 整理:韩非 本文主要整理自云栖大会阿里巴巴计算平台事业部资深技术专家王峰(花名:莫问)在云栖大会‘开发者生态峰会’上发表的演讲。 伴随着海量增长的数据,数字化时代的未来感扑面而至。
1671 0
|
2月前
|
消息中间件 Kafka Apache
Apache Flink 是一个开源的分布式流处理框架
Apache Flink 是一个开源的分布式流处理框架
482 5
|
1月前
|
消息中间件 API Apache
官宣|阿里巴巴捐赠的 Flink CDC 项目正式加入 Apache 基金会
本文整理自阿里云开源大数据平台徐榜江 (雪尽),关于阿里巴巴捐赠的 Flink CDC 项目正式加入 Apache 基金会。
1414 1
官宣|阿里巴巴捐赠的 Flink CDC 项目正式加入 Apache 基金会
|
1月前
|
SQL Java API
官宣|Apache Flink 1.19 发布公告
Apache Flink PMC(项目管理委员)很高兴地宣布发布 Apache Flink 1.19.0。
1355 1
官宣|Apache Flink 1.19 发布公告
|
1月前
|
SQL Apache 流计算
Apache Flink官方网站提供了关于如何使用Docker进行Flink CDC测试的文档
【2月更文挑战第25天】Apache Flink官方网站提供了关于如何使用Docker进行Flink CDC测试的文档
143 3
|
1月前
|
Oracle 关系型数据库 流计算
flink cdc 同步问题之报错org.apache.flink.util.SerializedThrowable:如何解决
Flink CDC(Change Data Capture)是一个基于Apache Flink的实时数据变更捕获库,用于实现数据库的实时同步和变更流的处理;在本汇总中,我们组织了关于Flink CDC产品在实践中用户经常提出的问题及其解答,目的是辅助用户更好地理解和应用这一技术,优化实时数据处理流程。

热门文章

最新文章

推荐镜像

更多