场景
在日常开发中,我们经常需要给对象进行赋值,通常会调用其 set/get 方法,
有些时候,如果我们要转换的两个对象之间属性大致相同,会考虑使用属性拷贝工具进行。
如我们经常在代码中会对一个数据结构封装成 DO、SDO、DTO、VO 等,而这些 Bean 中的大部分属性都是一样的,
所以使用属性拷贝类工具可以帮助我们节省大量的 set 和 get 操作
为什么java开发手册中提到禁止使用Apache BeanUtils 进行属性的copy
说明:Apache BeanUtils 性能较差,可以使用其他方案比如Spring BeanUtils,Cglib BeanCopier,注意均是浅拷贝。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
为了验证以上原因,变写测试代码进行验证。
1、首先项目中引入Apache Beanutils 依赖
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
2、新建PersonDO与PersonDTO以便进行属性复制
PersonDO:
import lombok.Data;
import java.util.Date;
@Data
public class PersonDO {
private Integer id;
private String name;
private Integer age;
private Date birthday;
}
PersonDTO:
import lombok.Data;
import java.util.Date;
@Data
public class PersonDTO {
private String name;
private Integer age;
private Date birthday;
}
3、构建PersonDo对象并赋值属性,并将同类别的属性复制的工具类进行一百万次测试方法的封装。
PersonDO personDO = new PersonDO();
personDO.setName("霸道的程序猿");
personDO.setAge(30);
personDO.setBirthday(new Date());
personDO.setId(1);
4、Java中封装使用ApacheBeanUtils进行指定次数属性复制的方法
public static 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();
org.apache.commons.beanutils.BeanUtils.copyProperties(personDTO,personDO);
}
stopWatch.stop();
System.out.println("mappingByApacheBeanUtils cost:"+stopWatch.getTotalTimeMillis());
}
5、Java中封装使用SpringBeanUtils进行指定次数属性复制的方法
public static 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());
}
6、Java中封装使用CglibBeanCopier进行指定次数属性复制的方法
public static 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());
}
7、Java中封装使用ApachePropertyUtils进行指定次数属性复制的方法
public static 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();
org.apache.commons.beanutils.PropertyUtils.copyProperties(personDTO,personDO);
}
stopWatch.stop();
System.out.println("mappingByApachePropertyUtils cost:"+stopWatch.getTotalTimeMillis());
}
8、以上工具类执行属性复制的次数均设置为一百万次,然后执行对比效果
总结:如果考虑性能情况的话,建议大家不要选择 Apache PropertyUtils、BeanUtils,
是因为 Apache BeanUtils 力求做得完美 , 在代码中增加了非常多的校验、兼容、日志打印等代码,
过度的包装导致性能下降严重。