Java 对象复制 Java对象复制6种情况 效率对比 BeanUtils 对象复制 Dozer 复习复制 MapStruct对象复制

一、概述

在Java开发中,经常会遇到对象的复制转换操作,各种xxAO , 转换到 xxBO , 这就涉及到对象之间的复制。 例如:把 Pig 对象复制到 PigDTO 对象中 …

在Java中,目前据我所知可以做到对象复制的相关工具有以下 6 种:

1、Spring BeanUtils2、Apache BeanUtils3、Dozer4、Hutool BeanUtil5、cglib BeanCopier 6、MapStruct

本文将对比这6中对象复制的效率情况。

二、准备工作

1、Apache BeanUtils 依赖

commons-beanutilscommons-beanutils1.9.1

2、Dozer 依赖

 net.sf.dozer dozer 5.5.1

3、Hutool 依赖

 cn.hutool hutool-all 5.7.18

4、cglib BeanCopier 依赖

org.springframeworkspring-core5.1.4.RELEASE-- 或使用 cglib 依赖 cglib cglib 3.3.0

5、MapStructs 依赖

 org.mapstruct mapstruct-jdk8 1.3.0.Final org.mapstruct mapstruct-processor 1.3.0.Final

6、Java Bean Pig 和 PigDTO

import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.util.List;@NoArgsConstructor@AllArgsConstructor@Datapublic class Pig {private int id ;private String name ;private List list ;}@NoArgsConstructor@AllArgsConstructor@Datapublic class PigDTO {private int id ;private String name ;private List list ;}

三、效率对比

1、springBeanUtils 复制

public void springBeanUtils(Pig a ,PigDTO b){org.springframework.beans.BeanUtils.copyProperties(a,b);}

2、apacheBeanUtils 复制

public void apacheBeanUtils(Pig a ,PigDTO b) throws InvocationTargetException, IllegalAccessException {org.apache.commons.beanutils.BeanUtils.copyProperties(b,a);}

3、dozer 复制

public static class DozerUtil{static Mapper MAPPER = new DozerBeanMapper();/** * Description: 普通对象转换 * @param src * @param dest * @return T * @version v1.0 * @author wu * @date 2023/4/18 14:09 */ public static T map(Object src , Class dest){ if(Objects.isNull(src)){ return null; } return MAPPER.map(src,dest); } }

4、hutoolBeanUtil 复制

public void hutoolBeanUtil(Pig a ,PigDTO b){BeanUtil.copyProperties(a,b);}

5、cglibBeanCopier 复制

public void cglibBeanCopier(Pig a ,PigDTO b){final BeanCopier beanCopier = BeanCopier.create(a.getClass(), b.getClass(),false);beanCopier.copy(a,b,null);}

6、mapStrctCopyObj 复制

import com.runcode.springboottourist.beanutil.bean.Pig;import com.runcode.springboottourist.beanutil.bean.PigDTO;import org.mapstruct.Mapper;@Mapperpublic interface MapStrctMapping {PigDTO pigToPigDTO(Pig pig);PigDTO pigToPigDTO2(Pig pig);}// 复制代码public PigDTO mapStrctCopyObj(Pig pig ){final MapStrctMapping mapper = Mappers.getMapper(MapStrctMapping.class);final PigDTO pigDTO = mapper.pigToPigDTO(pig);return pigDTO;}

7、复制效率测试

final Pig pig = new Pig(11, "二狗子", Lists.newArrayList("aaa", "bbb", "ccc"));@Testpublic void springBeanUtilsBatchTest() throws Exception{int count = 1000 ;StopWatch stopWatch = StopWatch.createStarted();System.out.println("springBeanUtils 复制 ,"+count +" 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO pigDTO = new PigDTO();springBeanUtils(pig,pigDTO);}stopWatch.stop();System.out.println("springBeanUtils 复制 ,"+count +" 次数据,结束, 耗时:"+ stopWatch.getTime()+" , 毫秒");}@Testpublic void apacheBeanUtilsBatchTest() throws Exception {int count = 1000;StopWatch stopWatch = StopWatch.createStarted();System.out.println("apacheBeanUtilsBatchTest 复制 ," + count + " 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO pigDTO = new PigDTO();apacheBeanUtils(pig,pigDTO);}stopWatch.stop();System.out.println("apacheBeanUtilsBatchTest 复制 ," + count + " 次数据,结束, 耗时:" + stopWatch.getTime() + " , 毫秒");}@Testpublic void dozerBatchTest() throws Exception{int count = 1000;StopWatch stopWatch = StopWatch.createStarted();System.out.println("dozerBatchTest 复制 ," + count + " 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO dozer = dozer(pig, PigDTO.class);}stopWatch.stop();System.out.println("dozerBatchTest 复制 ," + count + " 次数据,结束, 耗时:" + stopWatch.getTime() + " , 毫秒");}@Testpublic void hutoolBeanUtilBatchTest() throws Exception{int count = 1000;StopWatch stopWatch = StopWatch.createStarted();System.out.println("hutoolBeanUtilBatchTest 复制 ," + count + " 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO pigDTO = new PigDTO();hutoolBeanUtil(pig,pigDTO);}stopWatch.stop();System.out.println("hutoolBeanUtilBatchTest 复制 ," + count + " 次数据,结束, 耗时:" + stopWatch.getTime() + " , 毫秒");}@Testpublic void cglibBeanCopierBatchTest() throws Exception{int count = 1000;StopWatch stopWatch = StopWatch.createStarted();System.out.println("cglibBeanCopierBatchTest 复制 ," + count + " 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO pigDTO = new PigDTO();cglibBeanCopier(pig,pigDTO);}stopWatch.stop();System.out.println("cglibBeanCopierBatchTest 复制 ," + count + " 次数据,结束, 耗时:" + stopWatch.getTime() + " , 毫秒");}@Testpublic void mapStrctCopyObjBatchTest() throws Exception{int count = 1000;StopWatch stopWatch = StopWatch.createStarted();System.out.println("mapStrctCopyObjBatchTest 复制 ," + count + " 次数据,开始====");for (int i = 0; i < count; i++) {final PigDTO pigDTO = new PigDTO();final PigDTO pigDTO1 = mapStrctCopyObj(pig);}stopWatch.stop();System.out.println("mapStrctCopyObjBatchTest 复制 ," + count + " 次数据,结束, 耗时:" + stopWatch.getTime() + " , 毫秒");}

8、结果如下:

1. Spring BeanUtils 耗时:361 ms2. Apache BeanUtils 耗时: 389 ms3. Dozer 耗时: 536 ms4. Hutool BeanUtil 耗时: 261 ms5. cglib BeanCopier 耗时: 155 ms6. MapStruct 耗时:30 ms

四、总结

1、复制效率情况如下:

MapStruct > cglib BeanCopier > Hutool BeanUtil > Spring BeanUtils >Apache BeanUtils > Dozer 

2、从数据对比结果上看:

复制效率最快的是 MapStruct , 其原理是 动态的生成对应bean的 getter/setter方法来实现复制; 最慢的是 Dozer 不建议在项目中使用

3、Apache BeanUtils 效率低:

一直提到 Apache BeanUtils 效率低下的问题,综合数据看 和 Spring BeanUtils 效率大概差不多。我这边分别用的版本是: Apache 1.9.1 Spring 5.1.4.RELEASE

4、关于 MapStruct:

GitHub – mapstruct/mapstruct: An annotation processor for generating type-safe bean mappers , 有兴趣自己去研究。