MapStruct 实践
MapStruct
简介
MapStruct
是一个代码生成器,它基于约定优于配置方法极大地简化了 Java bean 类型之间映射的实现。生成的映射代码使用简单的方法调用,因此速度快、类型安全且易于理解。MapStruct
是一个注解处理器,它插入到 Java 编译器中,可用于命令行构建(Maven、Gradle 等)或者IDE。MapStruct
使用合理的默认值,但在配置或实现特殊行为时会避开自定义的实现方式。MapStruct Spring Extensions
已经加入到org.springframework.core.convert
包中作为一种转换的实现提供使用
目的
在分布式架构(或微服务架构)需要拆分模块时,不得不思考一个问题:WEB 层能不能出现 DAO 或者 DO 对象?我觉得不行。服务层和表现层应当解耦,后者不应当触碰到任何持久化对象,其所有的数据来源,均应当由前者提供 ,而这需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct
旨在通过尽可能自动化来简化这项工作。映射代码的工具有很多种,如各种BeanUtils
等,与其他映射框架相比,MapStruct
在编译时生成 bean 映射,以确保高性能和安全.
对比
数据流对比 可以看 5种常见Bean映射工具的性能比对 (juejin.cn)
市面上还是有很多的相关代码映射工具,如
ModelMapper
(GitHub - modelmapper/modelmapper: Intelligent object mapping)BeanUtils
selma
(GitHub - xebia-france/selma: Selma Java bean mapping that compiles)mapstruct
- ...
以上工具可以大概分为2类
- **通过反射调用
set/get
或者直接对成员变量赋值, 一般都是调用反射包的invoke
方法 **BeanUtils
都是通过java.beans.PropertyDescriptor
和reflect
包来进行对应的处理,apache 支持名称相同但类型不同的属性的转换,spring 支持忽略某些属性不进行映射ModelMapper
也是在reflect
包封装反射支持的
- 编译期动态生成set/get代码的class文件 ,在运行时直接调用该class文件。
selma
使用静态编译生成字节码,而不会在运行时或在字符串字段中编写的伪代码进行任何反射。mapStruct
是最初提出了映射生成的想法,功能更加丰富,社区建设比较好
从性能、问题排查、文档、成熟度、扩展性等因素来考虑,MapStruct
是一个不错的选择;
使用篇
基础使用
-
pom
加载依赖此外,需要加载maven的
compiler
插件 -
编写对应的转换实体和转换Mapper
-
CarEntity
-
CarDTO
-
CarMapper
CarMapper
有多种 实现方式,建议如果要使用Mapper的话,继承org.springframework.core.convert.converter.Converter
,2个类的成员变量基本相同的情况下,可以不用做额外的方法处理,Mapper
最常见的还是以下2种- 声明为
SpringBean
- 生成静态常量
2种方式都行,代码如下
- 声明为
-
test
测试类采用的第二种方式进行的转换,可见在使用方面还是比较方便的
-
进阶使用方式
下面选择几个常用场景描述下
- 多参数
- 使用spring管理,不写常量类
3.调用其他的映射
- 直接将mapper中返回的值转换出去
- 指定字段使用指定方法转换
解析篇
框架实现依赖
mapStruct
采用了JDK6中的新特性 插入式注解处理API(Pluggable Annotation Processing API) ,lombok
注解,IDEA在编写代码时候的标记语法错误的红色下划线都是通过这个特性实现的.其主要抽象类是AbstractProcessor
,需要注意的是,该API只处理编译期注解
插入式注解处理API(JSR 269)提供一套标准API来处理Annotations(JSR 175),实际上JSR 269不仅仅用来处理Annotation,我觉得更强大的功能是它建立了Java 语言本身的一个模型,它把method, package, constructor, type, variable, enum, annotation等Java语言元素映射为Types和Elements, 从而将Java语言的语义映射成为对象, 我们可以在javax.lang.model包下面可以看到这些类. 所以我们可以利用JSR 269提供的API来构建一个功能丰富的元编程(metaprogramming)环境. JSR 269用Annotation Processor在编译期间而不是运行期间处理Annotation, Annotation Processor相当于编译器的一个插件,所以称为插入式注解处理.如果Annotation Processor处理Annotation时(执行process方法)产生了新的Java代码,编译器会再调用一次Annotation Processor,如果第二次处理还有新代码产生,就会接着调用Annotation Processor,直到没有新代码产生为止.每执行一次process()方法被称为一个"round",这样整个Annotation processing过程可以看作是一个round的序列. JSR 269主要被设计成为针对Tools或者容器的API.
注解API实现步骤
-
定义
annotation process
:org.mapstruct.ap.MappingProcessor
,并继承javax.annotation.processing.AbstractProcessor
-
定义注解
org.mapstruct.Mapper
,并将运行策略改成@Retention(RetentionPolicy.SOURCE)
-
在
MappingProcessor
中使用javax.annotation.processing.SupportedAnnotationTypes
指定在第2步创建的注解类型的名称(注意需要全类名,"包名.注解类型名称",否则会不生效) -
在
MappingProcessor
中使用javax.annotation.processing.SupportedSourceVersion
指定编译版本SourceVersion.latestSupported()
。 -
在
MappingProcessor
中使用javax.annotation.processing.SupportedOptions
指定编译参数。 -
指定processor参与编译
-
直接使用编译参数指定,
javac -processor org.mapstruct.ap.MappingProcessor Main.java
。 -
通过服务注册指定,就是
META-INF/services/javax.annotation.processing.Processor
文件中添加org.mapstruct.ap.MappingProcessor。 -
通过Maven的编译插件的配置指定如下:
-
框架流程
mapStruct
虽然说实现的功能流程简单
, 但是它巧妙利用了Types和Elements
,将复杂的class生成分析转成对应去处理,倒是有其独特和称赞的地方
项目测试地址
参考资料
__EOF__

本文链接:https://www.cnblogs.com/wzqshb/p/14907761.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗