博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MapStruct-实体映射处理器
阅读量:4281 次
发布时间:2019-05-27

本文共 4548 字,大约阅读时间需要 15 分钟。

MapStruct-实体映射处理器


对象映射大体分为两种:

  • 运行期:反射调用set/get 或者是直接对成员变量赋值 。 * 该方式通过invoke执行赋值,实现时一般会采用beanutil, Javassist等开源库。这类的代表:Dozer,ModelMapper
  • 编译期:动态生成set/get代码的class文件 ,在运行时直接调用该class文件。* 该方式实际上仍会存在set/get代码,只是不需要自己写了。 这类的代表:MapStruct,Selma,Orika

MapStruct简化Bean对象之间的映射处理,其实质就是set/get的自动处生成转换理,参考官网:

导入依赖包

compile('org.mapstruct:mapstruct-jdk8:1.2.0.Final')    annotationProcessor("org.mapstruct:mapstruct-processor:1.2.0.Final")

如果引入以上包后编译无法生效,需要导入以下配置:

plugins {        id 'net.ltgt.apt' version '0.15'    }    apply plugin: 'net.ltgt.apt-idea'    apply plugin: 'net.ltgt.apt-eclipse'    /**     * 配置mapstruct任务     * http://mapstruct.org/documentation/dev/reference/html/#_gradle     */    tasks.withType(JavaCompile) {        options.compilerArgs = [                '-Amapstruct.suppressGeneratorTimestamp=true',                //默认交由spring管理,在外部可以直接使用@Autowired注入mapper                '-Amapstruct.defaultComponentModel=spring',                '-Amapstruct.suppressGeneratorVersionInfoComment=true',                '-Amapstruct.unmappedTargetPolicy=IGNORE'        ]    }

1. PersonDto

定义数据源对象

public class PersonDto {    private String nameDto;    private int age;    private String address;    private String idno;    private double money;    private Date birthDate;}

2. Person

定义目标对象

public class Person {    private String name;    private int age;    private String address;    private String idno;    private double money;    private Date birthDate;}

注意:其中name属性和PersonDto的nameDto不是同名

3. PersonMapStruct

定义源、目标对象映射关联接口

@Mapper(componentModel = "spring")public interface PersonMapStruct {    PersonMapStruct INSTANCE = Mappers.getMapper(PersonMapStruct.class);    @Mappings({            @Mapping(source = "nameDto", target = "name"),//            @Mapping(target = "birthDate", expression = "java(org.apache.commons.lang3.time.DateFormatUtils.format(personDto.getBirthDate(),\"yyyy-MM-dd\"))")    })    Person dtoToPoByPersonDto(PersonDto personDto);}

注意

  • 如果属性名称完全相同则不做处理,相反不同属性名称之间的映射可以使用@Mapping(source = “nameDto”, target = “name”)

  • 可以使用一些高级特性,如expression属性可以定义java代码用以进行特殊处理

  • componentModel属性用于指定自动生成的接口实现类的组件类型

    这个属性支持四个值:default: 这是默认的情况,mapstruct不使用任何组件类型, 可以通过Mappers.getMapper(Class)方式获取自动生成的实例对象。cdi: the generated mapper is an application-scoped CDI bean and can be retrieved via @Injectspring: 生成的实现类上面会自动添加一个@Component注解,可以通过Spring的 @Autowired方式进行注入jsr330: 生成的实现类上会添加@javax.inject.Named 和@Singleton注解,可以通过 @Inject注解获取。

4. PersonMapStructImpl

编译完成后会生成接口的实现类

@Generated(    value = "org.mapstruct.ap.MappingProcessor",    date = "2019-01-28T17:18:38+0800",    comments = "version: 1.2.0.Final, compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)")@Componentpublic class PersonMapStructImpl implements PersonMapStruct {    @Override    public Person dtoToPoByPersonDto(PersonDto personDto) {        if ( personDto == null ) {            return null;        }        Person person = new Person();        person.setName( personDto.getNameDto() );        person.setAge( personDto.getAge() );        person.setAddress( personDto.getAddress() );        person.setIdno( personDto.getIdno() );        person.setMoney( personDto.getMoney() );        person.setBirthDate( personDto.getBirthDate() );        return person;    }}

注意:根据生成在target包下的源码可看出, mapstruct实则是生成了一些set/get方法,且对一些数据进行转换处理等

5. 使用

Person person = PersonMapStruct.INSTANCE.dtoToPoByPersonDto(personDto);

6. 性能测试

针对几种常见的Bean复制方式,分别进行简单的性能测试得出(单位:ms):

在这里插入图片描述

10次测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 131 130 137 132.667 13.2667
PropertyUtils.copyProperties 78 104 87 89.667 8.9667
spring.BeanUtils.copyProperties 1 1 1 1 0.1
BeanCopier.create 0 0 1 0.3333 0.0333
MapStruct 3 3 3 3 0.3
10000次测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 235 231 203 223 22.3
PropertyUtils.copyProperties 721 662 625 429.3092 42.9309
spring.BeanUtils.copyProperties 11 11 11 11 0.11
BeanCopier.create 2 2 3 2.3333 0.2333
MapStruct 5 5 9 6.3333 0.6333
100000次测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 500 570 572 547.3333 54.7333
PropertyUtils.copyProperties 3572 2475 3796 3281 328.1
spring.BeanUtils.copyProperties 58 55 51 54.6667 5.4667
BeanCopier.create 4 3 4 3.6667 0.3667
MapStruct 10 11 9 10 1

:内存12G、四核i7-4720QU处理器

根据测试结果得出,Cglib在测试中的优势较为明显,这得益于它的缓存机制,大家可以看下java.lang.reflect.WeakCache类,不过即便没有缓存,性能依旧是不错,几乎零消耗;PropertyUtils的结果随着调用增长,呈迅速增长趋势,相对spring的copy则是稳步增长,最后是MapStruct则相对平稳且相对来说很稳健,Cglib基于类反射代理,只拷贝名称和类型都相同的属性,所以当目标类的setter数目比getter少时,创建BeanCopier会失败而导致拷贝不成功,需要手动去处理

综上所述,相对来说,实现Bean拷贝的自动化处理,且侵入较小,性能也保证的前提下,Cglib和MapStruct都是不错的选择,不过对于更好的自定义和可读性来说,推荐MapStruct。

转载地址:http://uifgi.baihongyu.com/

你可能感兴趣的文章
Linux电源管理(8)_Wakeup count功能
查看>>
Linux电源管理(9)_wakelocks
查看>>
Linux电源管理(10)_autosleep
查看>>
Linux电源管理(11)_Runtime PM之功能描述
查看>>
linux下,如何debug Suspend and resume
查看>>
Linux时间子系统之(一):时间的基本概念
查看>>
Linux时间子系统之(二):软件架构
查看>>
objdump命令的使用
查看>>
linux下如何打开core dump
查看>>
Linux时间子系统之(三):用户空间接口函数
查看>>
Linux时间子系统之(四):timekeeping
查看>>
How to modify linux time
查看>>
repo 的使用
查看>>
cmake 命令 安装,用法简介
查看>>
Intel Edison C++ 开发之I2C-使用MRAA库进行C/C++开发
查看>>
Intel Edison C++ 开发之I2C-深入MRAA开发
查看>>
android中wifi的上下层的连接、命令发送
查看>>
Android平台开发-WIFI function porting-WIFI功能移植
查看>>
wifi学习总结
查看>>
wifi 链接流程
查看>>