MapStruct使用指南以及原理解析

这篇具有很好参考价值的文章主要介绍了MapStruct使用指南以及原理解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关键词

JSR-269、编译原理、生成树AST、SPI机制、FreeMarker

要想搞懂mapstruct的底层实现原理,需要先知道java编译流程:.java源文件经过编译器编译成为.class文件,虚拟机执行的就是.class文件

一.语法树

抽象语法树(Abstract Syntax Tree,AST)是在编译器的编译过程中生成的一种数据结构,用于表示源代码的语法结构。

在 Java 的编译过程中,生成 AST 的步骤通常包括以下几个阶段:

词法分析(Lexical Analysis):也称为扫描(Scanning),将源代码分解成一个个的词法单元(Token)。词法单元可以是关键字、标识符、运算符、常量等。

语法分析(Syntax Analysis):也称为解析(Parsing),根据词法单元构建语法树。语法分析器使用文法规则(例如上下文无关文法)来检查词法单元是否符合语法规则,并生成抽象语法树。

语义分析(Semantic Analysis):在生成 AST 的同时,进行语义检查。语义分析器会对语法树进行类型检查、作用域分析、常量表达式计算等。它还会将符号链接到声明,以便后续引用。

中间代码生成(Intermediate Code Generation):有些编译器会在 AST 基础上生成一种中间表示形式,例如三地址码或虚拟机指令。这些中间代码通常更容易进行优化和目标代码生成。

目标代码生成(Code Generation):将 AST 或中间代码转换成目标平台的机器代码。这个阶段将 AST 的每个节点映射到目标机器的指令,生成可以直接执行的最终可执行文件。

因此,AST 的生成通常发生在词法分析和语义分析之间。它是编译过程中重要的中间表示形式,用于表示源代码的语法结构,并为后续的优化和代码生成提供基础。

二.lombok原理

lombok与MapStruct原理都是基于JSR-269规范:

初次使用lombok时,都需要在idea安装lombok插件,这让我们怀疑lombok的实现是通过提供自己的编译器实现的,然而实际情况并非如此,在脱离idea使用javac编译时,只要类路径有lombok的jar包,项

目也可以正常编译通过。其原理在于JSR-269规范。

1.JSR-269规范

JSR 269 规范定义了 Java 编译时注解处理器 API(Pluggable Annotation Processing API(插件式注解处理器)),提供了一种标准的方式让开发者在编译时自动
化处理 Java 源代码中的注解
。具体步骤如下:

  1. 自定义注解

  2. 继承AbstractProcessor类,重写process方法实现自己的注解处理逻辑

说明:AbstractProcessor在JDK的rt.jar里面的javax.annotation.processing包下面;同时生成impl类用的也是这个包下面的Filer接口的createSourceFile方法,SupportedAnnotationTypes注解、SupportedOptions注解、SupportedSourceVersion注解也都在,这三个注解目前只看到Mapstruct底层有用到
MapStruct使用指南以及原理解析

  1. 在META-INF/services目录下创建javax.annotation.processing.Processor文件注册自己实现的Annotation Processor(全路径名)

  2. 编译项目并deploy jar包到maven仓库,在其他项目引入该jar包,在接口上加上我们自定义的注解

在javac编译时即可调用到我们的注解处理器Annotation Processor,从而使得我们有机会对java编译过程中生产的抽象语法树进行修改。

2.原理

javac的编译过程,大致可以分为3个过程:

(1)解析与填充符号表过程

(2)插入式注解处理器的注解处理过程

(3)分析与字节码生成过程

解析与填充符号表过程会将源码转换为一棵抽象语法树(Abstract Syntax Tree,AST),AST是一种用来描述程序代码语法结构的树形表示方式,语法树的每一个节点(每个节点都是JCTree类的子类)都代表着程序代码中的一个语法结构
(Construct),例如包、类型、修饰符、运算符、接口、返回值甚至代码注释等都可以是一个语法结构。在插入式注解处理器的注解处理过程中,lombok对第一步骤得到的AST进行处理,找到类似@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),(TreeMaker提供方法可以修改)增加getter和setter等方法的相应树节点,javac使用修改后的抽象语法树(AST)生成字节码文件,因此最终生成的class文件中包含了这些
自动生成的getter,setter方法。

二.mapstruct原理

MapStruct 是用于 Bean 之间映射的工具库之一,其底层实现就是基于JSR-269。
阅读源码

(1)发现 mapstruct主要有两个jar包

MapStruct使用指南以及原理解析


(2)通过根据JSR-269可以知道MappingProcessor就是mapstruct的入口

MapStruct使用指南以及原理解析


(3)com.sun.tools.javac.main.JavaCompiler#compile方法的有段代码在编译的时候会调用到MappingProcessor

说明

com.sun.tools.javac.main.JavaCompiler 是 Java 编译器的主要类,它是 JDK 中 javac 命令行工具的实现。该类负责解析和编译 Java 源代码,并生成字节码文件。
JavaCompiler 类位于 com.sun.tools.javac.main 包中,属于 JDK 内部实现的一部分,并不是公开的 API。它提供了编译 Java 代码的核心功能

MapStruct使用指南以及原理解析


(4)Mapper注解定义如下

MapStruct使用指南以及原理解析


(5)MappingProcessor实现如下

MapStruct使用指南以及原理解析


process方法实现注解处理逻辑做代码改造工作。

MapStruct使用指南以及原理解析


(6)impl实现类生成

proess方法-->
processMapperElements( deferredMappers, roundContext );
-->processMapperTypeElement( context, mapperElement );
--->model = process( context, processor, mapperTypeElement, model );
--->processor.process( context, mapperTypeElement, sourceElement );
--->MapperRenderingProcessor类里可以看到有个createSourceFile方法(Filer 接口),该方法会创建xxxxImpl类。
MapStruct使用指南以及原理解析


另外,MapStruct 库的注解处理器生成源代码文件利用了模板引擎 FreeMarker 库。如图可以看到FreeMarker利用模板生成setter方法

MapStruct使用指南以及原理解析


如下后缀为ftl的文件即为FreeMarker模板文件
MapStruct使用指南以及原理解析

三.Debug模式跟踪代码

  1. 打开你的项目并转到 "Run/Debug Configurations" 对话框。
  2. 在左上角的工具栏中,点击下拉箭头旁边的 "Edit Configurations" 按钮。
  3. 在弹出的对话框中,选择 "Maven" 选项,并点击加号按钮以创建一个新的Maven配置。
  4. Command line输入"Compile"
  5. 选择项目工程然后apply

参考链接:
https://juejin.cn/post/6956190395319451679
https://blog.csdn.net/weixin_43983762/article/details/105867398
https://blog.csdn.net/begefefsef/article/details/126434950
https://developer.aliyun.com/article/944036
https://nullwy.me/2017/04/javac-api/

以下是来自chatgpt的回答:

1.MapStruct原理
是一个Java注解处理器,它基于编译时代码生成的原理,用于自动化Java bean类型之间的映射工作。以下是MapStruct的工作原理的详细解读:

注解处理: 在Java编译阶段,MapStruct通过Java的注解处理器API(JSR 269)扫描源代码中的接口或抽象类,这些接口或抽象类使用了MapStruct提供的注解,如@Mapper或@Mapping。

抽象方法解析: MapStruct分析这些接口或抽象类中定义的抽象方法,这些方法通常表示从一个bean类型转换到另一个bean类型的映射。MapStruct解析方法参数和返回值,确定源类型和目标类型。

属性映射分析: MapStruct使用内置的策略或者通过@Mapping注解指定的策略来分析两个bean之间属性的对应关系。如果属性名称相同且类型兼容,MapStruct会自动映射这些属性。

代码生成: 一旦分析完毕,MapStruct会为每个映射接口生成一个实现类。这个实现类包含了具体的映射逻辑,能够将一个对象的属性复制到另一个对象的相应属性中。

编译时优化: 因为所有的映射代码都是在编译时生成的,所以运行时没有反射的开销,这意味着MapStruct生成的代码在性能上与手写的映射代码类似。

类型转换: 如果源属性和目标属性的类型不匹配,MapStruct会尝试使用内置的类型转换器或者开发者可以自定义转换逻辑来进行转换。

嵌套属性和集合: MapStruct也支持嵌套属性的映射和集合类型的映射,允许复杂的数据结构之间的转换。

更新现有对象: 除了创建目标类型的新实例之外,MapStruct还允许将属性映射到现有的实例上。

构建工具集成: MapStruct可以很容易地与Maven或Gradle等构建工具集成,自动在编译过程中执行代码生成。

IDE集成: 由于MapStruct是在编译时生成代码,所以大多数Java IDE都能够很好地支持MapStruct,包括在生成的实现类中进行代码跳转和调试。

综上所述,MapStruct的主要优点是它通过在编译时生成映射代码,从而提供快速、类型安全并且易于维护的映射代码,而不需要开发者手动编写大量的映射逻辑。

2.Java的注解处理器API(JSR 269)说明如下
Java的注解处理器API(JSR 269),正式名称为Pluggable Annotation Processing API,是Java SE 6中引入的一项功能,允许开发者创建自定义注解处理器,这些处理器在编译时可以检查和处理注解。这是MapStruct工作原理的核心部分。以下是注解处理器如何在MapStruct中工作的详细说明:

编译器集成: 注解处理器在Java编译器(javac)的编译过程中运行。当javac编译Java源代码时,它会检查源代码中使用的注解。

发现注解处理器: 开发者可以通过在服务配置文件中声明或者使用编译器参数来指定注解处理器。MapStruct的注解处理器被声明在META-INF/services/javax.annotation.processing.Processor文件中,所以javac能够自动加载并调用它。

处理注解: 一旦javac发现了MapStruct的注解处理器,它会将所有使用了MapStruct注解(如@Mapper)的源代码元素(类、接口、方法等)传递给处理器。MapStruct的处理器会分析这些元素。

抽象语法树(AST): 注解处理器可以访问抽象语法树(AST),这是源代码的一个结构化表示。通过AST,处理器可以读取类、方法、字段和它们的注解等信息。

生成代码: 注解处理器可以生成新的源代码文件。MapStruct的处理器使用这个能力来生成实现了映射接口的具体类。这些生成的类包含了必要的映射逻辑,将一个对象的属性转换到另一个对象。

类型检查: 注解处理器还可以进行类型检查,确认注解的使用是否符合预期的规则。如果不符合,它可以生成编译错误或警告。

环回机制: 如果注解处理器生成新的代码,这些代码可能包含新的注解,javac会在后续的编译轮次中处理这些新生成的代码。这个过程会一直进行,直到没有新的注解处理器输出为止。

多轮处理: 注解处理器可能会在多轮编译过程中运行。在每一轮中,处理器会接收到当前轮次未处理的注解类型。处理器必须管理它在每一轮中的状态,因为它可能需要在多轮中累积信息。

总结来说,MapStruct通过注解处理器在编译时分析使用了MapStruct注解的源代码,并生成相应的映射类。这一切都在Java编译器的控制之下进行,确保了生成的代码是即时和准确的,而且不会对运行时性能产生影响。

3.META-INF文件夹用来做什么的
META-INF目录是Java JAR文件的一部分,它用于存储JAR文件的元数据,也就是关于JAR包本身的数据和配置信息。这个目录通常包含以下几种类型的文件和子目录:

MANIFEST.MF: 这是JAR文件中最重要的文件之一,位于META-INF目录下。它包含了JAR文件的元数据,例如主类(Main-Class)的名称、JAR文件的版本、创建者信息、包的签名信息等。Java运行时使用这些信息来执行和验证JAR文件。

签名文件和签名块文件: 如果JAR文件被签名,那么签名文件(.SF或.DSA或.RSA文件)和签名块文件(.RSA或.DSA或.EC文件)会被放在META-INF目录下。这些文件用来验证JAR文件的完整性和来源。

服务提供者配置文件: 用于服务加载机制的配置文件(如javax.annotation.processing.Processor),它们通常放在META-INF/services目录下,这些文件用来指定服务接口的实现类,以供服务加载器使用。

其他资源文件: 除了上述文件外,META-INF目录还可以包含其他资源文件,如属性文件、配置文件、图片等,这些文件通常由JAR包内的应用程序使用。

索引文件: 有时候,META-INF目录还可能包含用于加速类加载的索引文件(如INDEX.LIST)。

在Java EE或者其他Java技术栈中(如OSGi),META-INF目录用途更广泛,可能包含如persistence.xml、beans.xml、ejb-jar.xml等更多特定于技术的配置文件。

因此,META-INF目录是JAR文件的一个重要组成部分,用于存储JAR包的元数据和配置信息,并且是Java平台中约定俗成用于此目的的目录。文章来源地址https://www.toymoban.com/news/detail-750690.html

到了这里,关于MapStruct使用指南以及原理解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MapStruct原理解析

    JSR-269、编译原理、生成树AST、SPI机制、FreeMarker 要想搞懂mapstruct的底层实现原理,需要先知道java编译流程:.java源文件经过编译器编译成为.class文件,虚拟机执行的就是.class文件 抽象语法树(Abstract Syntax Tree,AST)是在编译器的编译过程中生成的一种数据结构,用于表

    2024年02月05日
    浏览(24)
  • Python JSON 使用指南:解析和转换数据

    JSON 是一种用于存储和交换数据的语法。JSON 是文本,使用 JavaScript 对象表示法编写。 Python 有一个内置的 json 包,可用于处理 JSON 数据。 示例 :导入 json 模块: 如果您有一个 JSON 字符串,可以使用 json.loads() 方法来解析它。结果将是一个 Python 字典。 示例 :从 JSON 转换为

    2024年02月06日
    浏览(35)
  • IDA的详细使用指南以及核心功能讲解

    首先打开网页搜索吾爱破解,进入吾爱破解官网,找到逆向资源区栏目 在该栏目中找到IDA软件资源 点击进入,获取网盘地址以及提取码 进入网盘进行下载 下载好之后打开压缩包,将可执行文件添加桌面快捷方式 此时即可点击使用IDA软件 2.1、打开与关闭 打开:我们双击ID

    2024年02月02日
    浏览(31)
  • SQLite数据库使用指南以及相关API编程

    SQLite是一种基于C语言开发的轻量级、快速、自包含、高可靠性和全功能的SQL数据库引擎。它是全球范围内使用最为广泛的数据库引擎,被嵌入到所有移动设备和大部分计算机中,并且伴随着无数日常使用的应用程序一起提供。 SQLite的文件格式具有稳定性、跨平台性以及向后

    2024年03月20日
    浏览(37)
  • MyBatis实战指南(二):工作原理与基础使用详解

    MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。那么,它是如何工作的呢?又如何进行基础的使用呢?本文将带你了解MyBatis的工作原理及基础使用。 1.1 MyBatis的工作原理 工作原理图示: 1、读取MyBatis配置文件 mybatis-config.xml为MyBatis的全局配置文件

    2024年02月02日
    浏览(24)
  • 深度解析:使用Postman调试微信支付接口的完美指南

    在使用 Postman 调试微信支付接口之前,你需要做好以下准备: 安装 Postman 客户端应用,或使用网页版; 成为 微信支付商户; 已申请 商户API私钥。 当你已经具备这三个条件,就可以进入微信支付接口调试之旅了~ 方式一:通过 fork 方式 为了帮助商户开发者快速上手,微信官

    2024年02月08日
    浏览(27)
  • Maven中常用命令以及idea中使用maven指南

    compile compile 是maven 工程的编译命令,作用是将src/main/java 下的文件编译为class 文件输出到target 目录下。 test test 是maven 工程的测试命令 mvn test,会执行src/test/java 下的单元测试类。 clean clean 是maven 工程的清理命令,执行clean 会删除target 目录及内容。 package package 是maven 工程的

    2024年02月05日
    浏览(32)
  • Stable Diffusion VAE:改善图像质量的原理、选型与使用指南

    VAE Stable Diffusion(稳定扩散)是一种用于生成模型的算法,结合了变分自编码器(Variational Autoencoder,VAE)和扩散生成网络(Diffusion Generative Network)的思想。它通过对变分自编码器进行改进,提高了生成样本的质量和多样性。 VAE Stable Diffusion的核心思想是使用扩散生成网络来

    2024年02月14日
    浏览(37)
  • 【游戏】任天堂Nintendo Switch超详细购买/使用指南以及注意事项(根据自己使用持续更新中...)

    相信90后对于上面这张图片里的东西都很熟悉吧,各种游戏卡:超级玛丽,忍者龙剑传,忍者神龟,魂斗罗,热血篮球,冒险岛,双截龙,绿色兵团,洛克人,炸弹人,松鼠大战,赤色要塞等等。那时候一个超级玛丽,一玩就能玩一天,而超级玛丽就是任天堂开发的,而现在

    2024年02月10日
    浏览(28)
  • Cheat Enginee(CE)的详细使用指南~包含下载安装教程以及核心功能讲解

    首先:搜索并且进入官网,点击DownLoad按钮 选择下载路径:(根据自己计算机的实际情况进行下载) 下载完成后运行exe安装文件,并选择自己熟悉的语言,点击OK进入安装程序 点击NEXT按钮,继续安装 进入到ce修改器(Cheat Engine)许可协议界面,点击Accept按钮,同意协议 下载产品

    2024年02月01日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包