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 , 有兴趣自己去研究。