神器MapStruct,性能爆棚的实体转换 / 复制工具

Java项目中实体转化无处不在,当实体字段较多或许大批量的进行仿制时,经过手工setter/getter显得太LOW,同时兼备高性能要求情况下,MapStruct彻底彻底能够胜任。官方解说,MapStruct是一个代码生成器,它依据约好优于配置的办法,极大地简化了Java bean类型之间映射的完结。生成的映射代码运用一般办法调用,因此快速、类型安全且易于理解。由于MapStruct是在编译期间生成setter/getter办法,实际运行时便是直接调用setter/getter,效率会非常高。

优点

  • MapStruct编译期生成映射代码,所以能够在编译时暴露映射过错的代码,让过错提早暴露
  • 由于运用setter/getter办法,而非反射办法,所以能够更快的执行效率;
  • 能够完结拷贝,主动类型转化,如枚举转化;
  • 进行自界说的映射,多种映射办法,下边详细说明;

性能比照

比照方针 10个方针仿制1次 1万个方针仿制1次 100万个方针仿制1次 100万个方针仿制5次
MapStruct 0ms 3ms 96ms 281ms
Hutools的BeanUtil 23ms 102ms 1734ms 8316ms
Spring的BeanUtils 2ms 47ms 726ms 3676ms
Apache的BeanUtils 20ms 156ms 10658ms 52355ms
Apache的PropertyUtils 5ms 68ms 6767ms 30694ms

运用

依赖

<!-- MapStruct中心,包含了一些必要的注解-->
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <annotationProcessorPaths>
                    <!-- MapStruct编译,注解处理器,依据注解主动生成Mapper的完结 -->
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

界说转化接口

/**
 * 测验接口
 *
 * @author reboot
 */
@Mapper
public interface OrderConvertor {
    /**
     * 实例
     */
    OrderConvertor INSTANCE = Mappers.getMapper(OrderConvertor.class);
    /**
     * OrderDo -> OrderModel
     *
     * @param orderDo 订单实体
     * @return {@link OrderModel}
     */
    OrderModel toModel(OrderDo orderDo);
    /**
     * OrderDo -> OrderModel
     *
     * @param orderDos 订单实体
     * @return {@link OrderModel}
     */
    List<OrderModel> toModel(List<OrderDo> orderDos);
    /**
     * OrderModel -> OrderDo
     *
     * @param orderModel 订单模型
     * @return {@link OrderDo}
     */
    OrderDo toDo(OrderModel orderModel);
    /**
     * OrderModel -> OrderDo
     *
     * @param orderModels 订单模型
     * @return {@link OrderDo}
     */
    List<OrderDo> toDo(List<OrderModel> orderModels);
}

编译成果

神器MapStruct,性能爆棚的实体转换 / 复制工具

MapStruct会主动生成对应接口的完结,并主动完结特点映射联系,List会主动进行批量处理。

调用

/**
 * 订单服务
 *
 * @author reboot
 */
@Service
public class OrderService {
    /**
     * 获取订单列表
     *
     * @return {@link List}<{@link OrderModel}>
     */
    public List<OrderModel> getOrderList() {
        // 获取数据库数据DO
        List<OrderDo> result = selectOrderList();
        // 参数转化
        return OrderConvertor.INSTANCE.toModel(result);
    }
}

插件

神器MapStruct,性能爆棚的实体转换 / 复制工具

上边的运用办法尽管能够正常运用,但是在一些特点配置映射上和提示上,如果运用插件能够提升运用体会,IDEA中能够直接安装Mapstruct Support插件,当然Eclipse也有对应的插件。

特性

  • 杰出显现方针特点和源特点。将方针特点和源特点转到声明的setter / getter中;
  • 过错和快速修正:
    • 缺少@Mapper或@MapperConfig注解检查;
    • 快速修正未映射的方针特点,增加未映射方针特点和忽略未映射方针特点;

神器MapStruct,性能爆棚的实体转换 / 复制工具

其他用法

愈加详细的内容能够检查官方文档,发布文章时最新版本是 MapStruct 1.5.3.Final.html。

根底映射

@Mapper
public interface CarMapper {
    @Mapping(target = "manufacturer", source = "make")
    @Mapping(target = "seatCount", source = "numberOfSeats")
    CarDto carToCarDto(Car car);
    @Mapping(target = "fullName", source = "name")
    PersonDto personToPersonDto(Person person);
}

target表明方针特点名,source表明源特点名,一般在方针特点和源特点不同时运用,相同的特点名会主动进行映射。

映射器增加自界说办法

@Mapper
public interface CarMapper {
    @Mapping(...)
    ...
    CarDto carToCarDto(Car car);
    default PersonDto personToPersonDto(Person person) {
        //hand-written mapping logic
    }
}

自界说办法personToPersonDto并完结,在生成的完结类中会进行覆盖运用。

多个源参数映射

@Mapper
public interface AddressMapper {
    @Mapping(target = "description", source = "person.description")
    @Mapping(target = "houseNumber", source = "address.houseNo")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
    @Mapping(target = "description", source = "person.description")
    @Mapping(target = "houseNumber", source = "hn")
    DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}

存在多个源参数,运用参数名.特点名的办法进行表明,也能够直接运用根底类型的特点称号。

嵌套特点映射到当时方针

@Mapper
 public interface CustomerMapper {
     @Mapping( target = "name", source = "record.name" )
     @Mapping( target = ".", source = "record" )
     @Mapping( target = ".", source = "account" )
     Customer customerDtoToCustomer(CustomerDto customerDto);
 }

当源参数中存在方针特点,能够手动进行映射,或许直接运用”.”的办法将方针中的特点悉数映射到当时方针方针。

表达式办法

@Mapper
public interface SourceTargetMapper {
    SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
    @Mapping(
        target = "timeAndFormat",
        expression = "java( new org.sample.TimeAndFormat( s.getTime(), s.getFormat() ) )"
    )
    Target sourceToTarget(Source s);
}

支撑运用java代码块进行转化,一般能够将静态办法处理的字段放到这儿。

更新现有实例

@Mapper
public interface CarMapper {
    void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}

@MappingTarget源参数,编译时会将carDto参数中的特点映射到car参数中。

Map映射

@Mapper
public interface CustomerMapper {
    @Mapping(target = "name", source = "customerName")
    Customer toCustomer(Map<String, String> map);
}

直接将map中的key进行映射。

更多用法

还有更多其他用法,比如:

  • 支撑映射界说的public特点;
  • 支撑映射参数Builder模式;
  • 运用注入办法引入转化器;
  • 数据类型字段转化,如枚举、日期,支撑日期格式化,支撑数字类型格式化,详细能够看 Implicit type conversions;
  • 集合类型主动转化;
  • 转化Stream;
  • ……

总结

MapStruct还有许多其他高阶特性,限于篇幅文章只是列举部分示例,有爱好的同学能够检查对应文档试试。运用恰当的东西有用提高编程效率,在运用东西过程中我们也了解其完结原理,不断提高自身。后边有时间也把MapStruct完结原理拿出来讲讲,跟大家一起学习进步!