ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

丢弃掉那些BeanUtils工具类吧,MapStruct真香,mysql性能调优与架构设计PDF

2021-12-23 15:58:40  阅读:193  来源: 互联网

标签:架构设计 PersonDO String 映射 MapStruct 调优 personDO dto2do


org.mapstruct

mapstruct-processor

${org.mapstruct.version}

因为MapStruct需要在编译器生成转换代码,所以需要在maven-compiler-plugin插件中配置上对mapstruct-processor的引用。这部分在后文会再次介绍。

之后,我们需要定义一个做映射的接口,主要代码如下:

@Mapper

interface PersonConverter {

PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);

@Mappings(@Mapping(source = “name”, target = “userName”))

PersonDTO do2dto(PersonDO person);

}

使用注解@Mapper定义一个Converter接口,在其中定义一个do2dto方法,方法的入参类型是PersonDO,出参类型是PersonDTO,这个方法就用于将PersonDO转成PersonDTO。

测试代码如下:

public static void main(String[] args) {

PersonDO personDO = new PersonDO();

personDO.setName(“Hollis”);

personDO.setAge(26);

personDO.setBirthday(new Date());

personDO.setId(1);

personDO.setGender(Gender.MALE.name());    PersonDTO personDTO = PersonConverter.INSTANCE.do2dto(personDO);    System.out.println(personDTO);

}

输出结果:

PersonDTO{userName=‘Hollis’, age=26, birthday=Sat Aug 08 19:00:44 CST 2020, gender=MALE}

可以看到,我们使用MapStruct完美的将PersonDO转成了PersonDTO。

上面的代码可以看出,MapStruct的用法比较简单,主要依赖@Mapper注解。

但是我们知道,大多数情况下,我们需要互相转换的两个类之间的属性名称、类型等并不完全一致,还有些情况我们并不想直接做映射,那么该如何处理呢?

其实MapStruct在这方面也是做的很好的。

MapStruct处理字段映射

首先,可以明确的告诉大家,如果要转换的两个类中源对象属性与目标对象属性的类

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

型和名字一致的时候,会自动映射对应属性。

那么,如果遇到特殊情况如何处理呢?

名字不一致如何映射

=============

如上面的例子中,在PersonDO中用name表示用户名称,而在PersonDTO中使用userName表示用户名,那么如何进行参数映射呢。

这时候就要使用@Mapping注解了,只需要在方法签名上,使用该注解,并指明需要转换的源对象的名字和目标对象的名字就可以了,如将name的值映射给userName,可以使用如下方式:

@Mapping(source = “name”, target = “userName”)

可以自动映射的类型

=============

除了名字不一致以外,还有一种特殊情况,那就是类型不一致,如上面的例子中,在PersonDO中用String类型表示用户性别,而在PersonDTO中使用一个Genter的枚举表示用户性别。

这时候类型不一致,就需要涉及到互相转换的问题

其实,MapStruct会对部分类型自动做映射,不需要我们做额外配置,如例子中我们将String类型自动转成了枚举类型。

一般情况下,对于以下情况可以做自动类型转换:

  • 基本类型及其他们对应的包装类型。

  • 基本类型的包装类型和String类型之间

  • String类型和枚举类型之间

自定义常量

=========

如果我们在转换映射过程中,想要给一些属性定义一个固定的值,这个时候可以使用 constant

@Mapping(source = “name”, constant = “hollis”)

类型不一致的如何映射

==============

还是上面的例子,如果我们需要在Person这个对象中增加家庭住址这个属性,那么我们一般在PersonoDTO中会单独定义一个HomeAddress类来表示家庭住址,而在Person类中,我们一般使用String类型表示家庭住址。

这就需要在HomeAddress和String之间使用JSON进行互相转化,这种情况下,MapStruct也是可以支持的。

public class PersonDO {

private String name;

private String address;

}public class PersonDTO {

private String userName;

private HomeAddress address;

}@Mapper

interface PersonConverter {

PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);

@Mapping(source = “userName”, target = “name”)

@Mapping(target = “address”,expression = “java(homeAddressToString(dto2do.getAddress()))”)

PersonDO dto2do(PersonDTO dto2do);

default String homeAddressToString(HomeAddress address){

return JSON.toJSONString(address);

}}

我们只需要在PersonConverter中在定义一个方法(因为PersonConverter是一个接口,所以在JDK 1.8以后的版本中可以定义一个default方法),这个方法的作用就是将HomeAddress转换成String类型。

default方法:Java 8 引入的新的语言特性,用关键字default来标注,被default所标注的方法,需要提供实现,而子类可以选择实现或者不实现该方法

然后在dto2do方法上,通过以下注解方式即可实现类型的转换:

@Mapping(target = “address”,expression = “java(homeAddressToString(dto2do.getAddress()))”)

上面这种是自定义的类型转换,还有一些类型的转换是MapStruct本身就支持的,如String和Date之间的转换:

@Mapping(target = “birthday”,dateFormat = “yyyy-MM-dd HH:mm:ss”)

以上,简单介绍了一些常用的字段映射的方法,也是我自己在工作中经常遇到的几个场景,更多的情况大家可以查看官方的示例(https://github.com/mapstruct/mapstruct-examples)。

MapStruct的性能

前面说了这么多MapStruct的用法,可以看出MapStruct的使用还是比较简单的,并且字段映射上面的功能很强大,那么他的性能到底怎么样呢?

参考《为什么阿里巴巴禁止使用Apache Beanutils进行属性的copy?》中的示例,我们对MapStruct进行性能测试。

分别执行1000、10000、100000、1000000次映射的耗时分别为:0ms、1ms、3ms、6ms。

可以看到,MapStruct的耗时相比较于其他几款工具来说是非常短的

那么,为什么MapStruct的性能可以这么好呢?

其实,MapStruct和其他几类框架最大的区别就是:与其他映射框架相比,MapStruct在编译时生成bean映射,这确保了高性能,可以提前将问题反馈出来,也使得开发人员可以彻底的错误检查。

还记得前面我们在引入MapStruct的依赖的时候,特别在maven-compiler-plugin中增加了mapstruct-processor的支持吗?

并且我们在代码中使用了很多MapStruct提供的注解,这使得在编译期,MapStruct就可以直接生成bean映射的代码,相当于代替我们写了很多setter和getter。

如我们在代码中定义了以下一个Mapper:

@Mapper

interface PersonConverter {

PersonConverter INSTANCE = Mappers.getMapper(PersonConverter.class);

@Mapping(source = “userName”, target = “name”)

@Mapping(target = “address”,expression = “java(homeAddressToString(dto2do.getAddress()))”)

@Mapping(target = “birthday”,dateFormat = “yyyy-MM-dd HH:mm:ss”)

PersonDO dto2do(PersonDTO dto2do);

default String homeAddressToString(HomeAddress address){

return JSON.toJSONString(address);

}}

经过代码编译后,会自动生成一个PersonConverterImpl:

@Generated(

value = “org.mapstruct.ap.MappingProcessor”,

date = “2020-08-09T12:58:41+0800”,

comments = “version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_181 (Oracle Corporation)”

)class PersonConverterImpl implements PersonConverter {

@Override

public PersonDO dto2do(PersonDTO dto2do) {

if ( dto2do == null ) {

return null;

}        PersonDO personDO = new PersonDO();

personDO.setName( dto2do.getUserName() );        if ( dto2do.getAge() != null ) {

personDO.setAge( dto2do.getAge() );        }        if ( dto2do.getGender() != null ) {

personDO.setGender( dto2do.getGender().name() );        }        personDO.setAddress( homeAddressToString(dto2do.getAddress()) );        return personDO;

}}

在运行期,对于bean进行映射的时候,就会直接调用PersonConverterImpl的dto2do方法,这样就没有什么特殊的事情要做了,只是在内存中进行set和get就可以了。

所以,因为在编译期做了很多事情,所以MapStruct在运行期的性能会很好,并且还有一个好处,那就是可以把问题的暴露提前到编译期。

使得如果代码中字段映射有问题,那么应用就会无法编译,强制开发者要解决这个问题才行。

总结
本文介绍了一款Java中的字段映射工具类,MapStruct,他的用法比较简单,并且功能非常完善,可以应付各种情况的字段映射。

标签:架构设计,PersonDO,String,映射,MapStruct,调优,personDO,dto2do
来源: https://blog.csdn.net/m0_65483413/article/details/122109698

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有