Java 对象复制 Java对象复制6种情况 效率对比 BeanUtils 对象复制 Dozer 复习复制 MapStruct对象复制
一、概述
在Java开发中,经常会遇到对象的复制转换操作,各种xxAO , 转换到 xxBO , 这就涉及到对象之间的复制。 例如:把 Pig 对象复制到 PigDTO 对象中 ...
在Java中,目前据我所知可以做到对象复制的相关工具有以下 6 种:
1、Spring BeanUtils
2、Apache BeanUtils
3、Dozer
4、Hutool BeanUtil
5、cglib BeanCopier
6、MapStruct
本文将对比这6中对象复制的效率情况。
二、准备工作
1、Apache BeanUtils 依赖
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.1</version>
</dependency>
2、Dozer 依赖
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
3、Hutool 依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.18</version>
</dependency>
4、cglib BeanCopier 依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
-- 或使用 cglib 依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
5、MapStructs 依赖
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</dependency>
6、Java Bean Pig 和 PigDTO
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Pig {
private int id ;
private String name ;
private List<String> list ;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class PigDTO {
private int id ;
private String name ;
private List<String> 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>T map(Object src , Class<T> 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;
@Mapper
public 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"));
@Test
public 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()+" , 毫秒");
}
@Test
public 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() + " , 毫秒");
}
@Test
public 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() + " , 毫秒");
}
@Test
public 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() + " , 毫秒");
}
@Test
public 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() + " , 毫秒");
}
@Test
public 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 ms
2. Apache BeanUtils 耗时: 389 ms
3. Dozer 耗时: 536 ms
4. Hutool BeanUtil 耗时: 261 ms
5. cglib BeanCopier 耗时: 155 ms
6. 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 , 有兴趣自己去研究。