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

目录
相关文章
|
Java Apache Spring
Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求
【5月更文挑战第4天】Spring BeanUtils与Apache BeanUtils提供基本属性复制,适用于简单需求;Cglib BeanCopier用于转换为Cglib代理对象;Apache PropertyUtils处理属性操作;Dozer支持复杂对象映射。选择工具取决于具体需求,如需精细控制或对象映射,推荐Dozer或Apache PropertyUtils。Apache BeanUtils可能因潜在的封装性破坏被禁用。
197 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呢
274 0
|
Java Apache Maven
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
我们到底应该选择哪种属性拷贝类工具更加合适呢?为什么阿里巴巴Java开发手册中提到禁止使用Apache BeanUtils呢?
12864 0
为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?
|
SQL 存储 资源调度
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
取之开源,用之开源——深度剖析阿里巴巴对Apache Flink的优化与改进
375 0
|
大数据 Apache 流计算
阿里巴巴编程之夏项目——Apache Flink
项目介绍: Apache Flink 是由 Apache 软件基金会开发的开源流处理框架,其核心是用 Java 和 Scala 编写的分布式流数据流引擎。Flink 以数据并行和流水线方式执行任意流数据程序,Flink 的流水线运行时系统可以执行批处理和流处理程序。
4700 0
|
SQL 大数据 API
阿里巴巴为什么选择Apache Flink?
作者:王峰 整理:韩非 本文主要整理自云栖大会阿里巴巴计算平台事业部资深技术专家王峰(花名:莫问)在云栖大会‘开发者生态峰会’上发表的演讲。 伴随着海量增长的数据,数字化时代的未来感扑面而至。
1930 0
|
6月前
|
人工智能 数据处理 API
阿里云、Ververica、Confluent 与 LinkedIn 携手推进流式创新,共筑基于 Apache Flink Agents 的智能体 AI 未来
Apache Flink Agents 是由阿里云、Ververica、Confluent 与 LinkedIn 联合推出的开源子项目,旨在基于 Flink 构建可扩展、事件驱动的生产级 AI 智能体框架,实现数据与智能的实时融合。
1058 6
阿里云、Ververica、Confluent 与 LinkedIn 携手推进流式创新,共筑基于 Apache Flink Agents 的智能体 AI 未来
|
存储 Cloud Native 数据处理
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
本文整理自阿里云资深技术专家、Apache Flink PMC 成员梅源在 Flink Forward Asia 新加坡 2025上的分享,深入解析 Flink 状态管理系统的发展历程,从核心设计到 Flink 2.0 存算分离架构,并展望未来基于流批一体的通用增量计算方向。
539 0
从嵌入式状态管理到云原生架构:Apache Flink 的演进与下一代增量计算范式
|
8月前
|
SQL 人工智能 数据挖掘
Apache Flink:从实时数据分析到实时AI
Apache Flink 是实时数据处理领域的核心技术,历经十年发展,已从学术项目成长为实时计算的事实标准。它在现代数据架构中发挥着关键作用,支持实时数据分析、湖仓集成及实时 AI 应用。随着 Flink 2.0 的发布,其在流式湖仓、AI 驱动决策等方面展现出强大潜力,正推动企业迈向智能化、实时化的新阶段。
902 9
Apache Flink:从实时数据分析到实时AI
|
8月前
|
SQL 人工智能 API
Apache Flink 2.1.0: 面向实时 Data + AI 全面升级,开启智能流处理新纪元
Apache Flink 2.1.0 正式发布,标志着实时数据处理引擎向统一 Data + AI 平台迈进。新版本强化了实时 AI 能力,支持通过 Flink SQL 和 Table API 创建及调用 AI 模型,新增 Model DDL、ML_PREDICT 表值函数等功能,实现端到端的实时 AI 工作流。同时增强了 Flink SQL 的流处理能力,引入 Process Table Functions(PTFs)、Variant 数据类型,优化流式 Join 及状态管理,显著提升作业稳定性与资源利用率。
793 0

推荐镜像

更多