美文网首页
还在使用BeanUtils.copyProperties()?来

还在使用BeanUtils.copyProperties()?来

作者: 花生无翼 | 来源:发表于2022-02-07 13:56 被阅读0次

最近在做性能优化,发现之前一个后台项目的接口有一些慢,仔细看看发现代码中有拷贝对象的逻辑,而且拷贝对象用到的还是BeanUtils.copyProperties()。在阿里巴巴编码规范插件中也是不支持使用这种方法进行拷贝的,如果有使用这种方法,用编码规约扫描会直接提示“避免用Apache Beanutils进行属性的copy”。同时会说明:“说明:Apache BeanUtils性能较差,可以使用其他方案比如Spring BeanUtils, Cglib BeanCopier”。除了建议的这几种方案外,还有一个更好的方案就是今天要介绍的MapsStruct。

1.定义

什么是MapStruct?

MapStruct 是一个代码生成器,它基于约定优于配置方法,极大地简化了Java bean类型之间映射的实现。生成的映射代码使用简单的方法调用,因此速度快、类型安全且易于理解。

2.实践

2.1工程引入Maven依赖
<dependency>
  <groupId>org.mapstruct</groupId>
  <!-- jdk8以下就使用mapstruct -->
  <artifactId>mapstruct-jdk8</artifactId>
  <version>1.3.0.Final</version>
</dependency>

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.6.2</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <annotationProcessorPaths>
            <path>
             <groupId>org.mapstruct</groupId>
             <artifactId>mapstruct-processor</artifactId>
             <version>1.3.0.Final</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>
2.2定义实体类

定义2个实体类,一个是User,一个是UserDTO,目标是把User的值拷贝到UserDTO

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
/**
 * 用户编号,主键
 */
private Long id;
/**
 * 用户名
 */
private String name;
/**
 * 电话
 */
private Long mobile;
/**
 * 年龄
 */
private Integer age;
/**
 * 性别
 */
private Integer sex;
/**
 * 家庭住址
 */
private String address;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
/**
 * 用户编号,主键
 */
private Long id;
/**
 * 用户名
 */
private String userName;
/**
 * 电话
 */
private Long mobile;
/**
 * 年龄
 */
private Integer age;
/**
 * 性别
 */
private Integer sex;
/**
 * 家庭住址
 */
private String address;
}

可以看到两个实体的字段名称不完全相同,这种情况下,不能使用BeanUtil.copyProperties()。使用MapStruct就可以处理这种情况,定义一个接口如下:
@Mapper
public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);

/**
 * 转换
 * @param user
 * @return
 */
@Mappings({
        @Mapping(source = "name", target = "userName"),
})
UserDTO convert(User user);

}
有拷贝对象的业务场景,直接使用如下代码:

   UserDTO userDTO1 = UserConvert.INSTANCE.convert(user);

原理就是通过JSR 269注解处理器在target自动生成接口定义的实现类,具体如下:


image.png

3.性能

对常用的几种方案做下性能上的对比,这样更能看出MapsStruts的效率,具体测试代码如下:

User user =  new User(1L,"小王",15800001111L,25,1,"中国北京朝阳");
long timeTaken;
long time1 = System.currentTimeMillis();
UserDTO userDTO;
for (int i = 0;i<500000;i++){
    userDTO = new UserDTO();
    org.apache.commons.beanutils.BeanUtils.copyProperties(userDTO,user);
}
long time2 = System.currentTimeMillis();
timeTaken =time2-time1;

System.out.println("Apache Commons BeanUtils:"+timeTaken+"(ms)");

long time3 = System.currentTimeMillis();

for (int i = 0;i<500000;i++){
    userDTO = new UserDTO();
    BeanUtils.copyProperties(user,userDTO);
}
long time4 = System.currentTimeMillis();

timeTaken =time4-time3;
System.out.println("Spring BeanUtils:"+timeTaken+"(ms)");

long time5 = System.currentTimeMillis();
for (int i = 0;i<500000;i++){
    UserDTO userDTO1 = UserConvert.INSTANCE.convert(user);
}
long time6 = System.currentTimeMillis();
timeTaken =time6-time5;

System.out.println("MapStruct:"+timeTaken+"(ms)");

long time7 = System.currentTimeMillis();
for (int i = 0;i<500000;i++){
    UserDTO userDTO1 =copyField(user);
}
long time8 = System.currentTimeMillis();
timeTaken =time8-time7;

System.out.println("Getter/Setter:"+timeTaken+"(ms)");

执行结果:

Apache Commons BeanUtils:5767(ms)
Spring BeanUtils:1102(ms)
MapStruct:14(ms)
Getter/Setter:14(ms)

看到上面的结果,可以得出结论Apache Commons BeanUtils确实耗时时间长,效率低,用Spring BeanUtils效率至少可以提高4倍,用MapStruct效率可以提高40倍,甚至可以和自己Getter/Setter的效率不相上下(注:效率倍数只是本次测试的数据,理论上转换的字段越多,循环次数越多,效果越明显)。

4.总结

本文主要讲了MapStruct的使用方法以及与其它拷贝对象方法的性能比较,着重突出MapStruct处理效率。除了上述实践中的简单使用,MapStruct还有许多其它的使用方法,具体内容可以看下它的官网(https://mapstruct.org)。
总的来说MapStruct是一个功能强大的创建映射器的工具库,可以减少开发人员编写一些基本模板代码的工作量,提高编码效率。

参考资料:
1.https://mapstruct.org/

相关文章

网友评论

      本文标题:还在使用BeanUtils.copyProperties()?来

      本文链接:https://www.haomeiwen.com/subject/icsmkrtx.html