java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > MapStruct解决Bean属性拷贝

MapStruct对象映射转换解决Bean属性拷贝性能问题

作者:心城以北

无意间看到项目中有小伙伴用到了 MapStruct 来做对象映射转换当时我就很好奇,这个是什么框架,能够解决什么问题,带着这两个疑问就有了下面的文章

简介

MapStruct 是一个代码生成器(可以生成对象映射转换的代码),它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。

生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。

适用场景

多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct 旨在通过尽可能地自动化来简化这项工作。

与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。

说白了就解决 beanCopy 的问题。

工作时机

MapStruct 是一个注解处理器,它插入到 Java 编译器中,可用于命令行构建(Maven、Gradle 等)以及您首选的 IDE。

MapStruct 使用合理的默认值,但在配置或实现特殊行为时会采取措施。

使用案例

1、添加依赖

// mapstruct
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
复制代码

2、定义两个类

一个 Car 类(JPA 实体类)

一个 CarDto 类(数据传输类)

这两个类型非常相似,只是在计数属性的字段名不同,并且 type 属性是 CarType 枚举类型,CarDto 中是字符串类型。

Car 类

public class Car {
    private String make;
    private int numberOfSeats;
    private CarType type;
    //constructor, getters, setters etc.
}

CarType 类定义

public enum CarType {
    SEDAN;
}

CarDto 类

public class CarDto {
    private String make;
    private int seatCount;
    private String type; 
    //constructor, getters, setters etc.
}

创建转换器类接口,定义需要将 Car 对象转换为 CarDto 对象

@Mapper
public interface CarMapper {
    CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
    @Mapping(source = "numberOfSeats", target = "seatCount")
    CarDto carToCarDto(Car car);
}

1). @Mapper 注解将该接口标记为映射接口,并且让 MapStruct 处理器在编译期间进行处理,实际映射方法为 carToCarDto 目的就是原参数Car,转换为方法返回结果对象 CarDto

2). 对于源对象和目标对象中有不同的属性名称,我们可以使用 @Mapping 注解进行映射。在默认情况下,将源对象和目标对象据欧不同的类型属性执行类型转换,例如,type 数据原来是枚举,可以自动转换为字符串。

3). 以一个 Mapper 接口也支持多个映射方法。所有的这些方法都由 MapStruct 框架来实现。我们可以从 Mappers类中检索接口实现的实例。通常我们在接口中申明一个 INSTANCE 属性,提供对外访问的实例。

3、单元测试

@Test
public void shouldMapCarToDto () {
    //given
    Car car = new Car("Morris", 5, CarType.SEDAN);
    //when
    CarDto carDto = CarMapper.INSTANCE.carToCarDto(car);
    //then
    assertThat(carDto).isNotNull();
    assertThat(carDto.getMake()).isEqualTo("Morris");
    assertThat(carDto.getSeatCount()).isEqualTo(5);
    assertThat(carDto.getType()).isEqualTo("SEDAN");
}

我们使用起来就是非常简单,运行结果如下:

核心总结

MapStruct其实和 Lombok 有些类似,也是通过插件的方式在我们编译期为我们生成一些辅助的代码。但是MapStruct 专注是解决 BeanCopy 以及对象转换的场景。

下面我们看看,就是我们 CarMapper 的实现类 CarMapperImpl , 这些都是框架在编译期间,我们生成的代码。

如果我们使用 BeanUtils.copyProperties来做对象的转换是需要通过反射来获取对象的属性,方法等信息。然后再去赋值。反射虽然能够解决一些通用性的场景,但是对于频繁的 List 复制,性能是不高的。我们可以看看下面copyProperties的部分代码截图:

个人觉得 MapStruct的优势还是非常明显的,就是帮助我们少写了非常多的 getters, setters 进行对象的相互转换,性能高于任何一种属性复制。缺点就会降低程序编译速度,增加转换层提升代码复杂度。

参考文档

以上就是MapStruct对象映射转换解决Bean属性拷贝性能问题的详细内容,更多关于MapStruct解决Bean属性拷贝的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文