场景
在日常开发中,我们经常需要给对象进行赋值,通常会调用其 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 力求做得完美 , 在代码中增加了非常多的校验、兼容、日志打印等代码,
过度的包装导致性能下降严重。