文章目录
- Java动态编译、JSR 269 和 MapStruct
- JSR 269
- JSR 269的工作原理
- MapStruct示例
- MappingProcessor
- 调试编译期生成的代码
Java动态编译、JSR 269 和 MapStruct
- Java动态编译是指在运行时动态地将Java源代码编译成字节码并加载到Java虚拟机中执行。
- JSR 269 是Java规范请求的一部分,它定义了一种标准的注解处理器API,允许开发人员在编译时扩展Java编译器的功能。
- JMapStruct 是一个基于 JSR 269 的Java注解处理器,用于生成类型安全的、高性能的、无依赖的Java bean映射代码。通过定义映射接口和相应的映射方法,MapStruct 在编译时生成这些接口的实现类,从而实现了类型安全的对象映射,避免了手动编写繁琐且容易出错的映射代码。
- MapStruct 使用注解处理器技术,结合了JSR 269的功能,实现了在编译时生成高效的映射代码,从而提供了更快的执行速度和更好的类型安全性。
JSR 269
JSR 269 Pluggable Annotation Processing API是Java社区规范,它允许开发者扩展Java编译器的注解处理能力。通过实现这个API,开发者可以创建自己的注解处理器,这些处理器可以在Java编译器(javac)运行时被调用,以处理特定的注解。
JSR 269的工作原理
- 编译器分析:javac对源代码进行分析,生成一棵抽象语法树(AST)。AST是源代码的抽象表示,其中包含了源代码的结构信息。
- 调用注解处理器:在编译过程中,javac会检查源代码中的注解,并根据这些注解调用相应的注解处理器。注解处理器是通过实现JSR 269 API创建的。
- 处理器逻辑:注解处理器可以执行自己的逻辑,例如修改AST,生成新的代码,或者进行代码分析。这个阶段,注解处理器可能会根据注解信息生成新的类、方法或字段。
- 生成字节码:javac使用修改后的AST生成字节码文件。这些字节码文件是Java程序的机器码表示,可以在JVM上运行。
MapStruct示例
MapStruct是一个代码生成库,它使用注解处理器来生成Java Bean属性映射器实现。MapStruct通过实现JSR 269 API,可以在编译时分析带有特定注解的Java类,并根据这些注解生成属性映射器代码。
例如,当你使用MapStruct注解来标注两个Java Bean类,并希望通过注解处理器生成它们之间的映射代码时,MapStruct的注解处理器就会被javac调用。这个处理器会分析注解,生成映射器的实现代码,然后将这些代码插入到AST中。最终,javac会生成包含映射器实现类的字节码文件。
通过这种方式,MapStruct极大地简化了Java Bean属性映射的实现,开发者不需要手动编写繁琐的映射代码,只需通过简单的注解即可。
总之,JSR 269 API为Java编译器提供了强大的扩展能力,使得开发者可以根据自己的需求在编译时进行代码的生成和修改。MapStruct是这种能力的典型应用,它通过注解处理器在编译时生成属性映射代码,提高了开发效率。
MappingProcessor
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version> <!-- 使用最新版本 -->
<scope>provided</scope>
</dependency>
在MapStruct的包结构中,有两个主要的包:
org.mapstruct:mapstruct
:这个包包含了MapStruct的核心注解,这些注解是用来在接口方法上描述映射规则的。主要的注解包括:
@Mapper
:用于标记一个接口为MapStruct的映射接口。@Mapping
:用于标记接口方法,表明该方法将会进行对象属性的映射。@Source
、@Target
、@AfterMapping
、@BeforeMapping
等:这些注解用于更精细地控制映射过程,比如指定源对象属性、目标对象属性、映射前后的操作等。
org.mapstruct:mapstruct-processor
:这个包包含了MapStruct的注解处理器,它是用于处理上述注解的逻辑,并在编译期生成实现类。这个处理器会读取带有@Mapper
注解的接口,并根据接口方法上的@Mapping
等注解来生成具体的映射实现代码。这样,开发者就不需要手动编写映射逻辑,提高了开发效率。
调试编译期生成的代码
MapStruct使用基于生成器的方法创建类型安全的映射代码,这些代码在编译时生成,那如何调测编译期生成的代码呢? 请继续看
想在IDEA中通过远程调试的方式对Maven项目进行调试。
- 切换到POM文件所在路径: 在终端(命令行界面)中,需要使用
cd
命令来切换到POM文件所在的目录。 或者找到pom 右键 如下
执行mvnDebug compile:
在终端中输入以下命令来执行Maven构建并启动调试:
mvnDebug compile
这里的mvnDebug
是Maven的调试模式,它会在编译时启动调试器。确保在执行此命令前已经正确设置了Maven的环境变量。
在IDEA中配置远程JVM调试:
打开IDEA,按照以下步骤配置远程JVM调试:
- 打开"Run" )菜单,选择"Edit Configurations"(编辑配置)。
- 在左侧列表中选择"Remote JVM Debug"。
- 在右侧的"Port"(端口)字段中输入8000,因为终端提示已经监听8000端口。
- 应用更改并关闭配置窗口。
- 打断点并进行调试:
- 在IDEA中打开您想要调试的Java文件。
- 在"JavaCompiler"类的"compile"方法处设置一个断点。
- 在"AbstractProcessor"类的"init"方法和"MappingProcessor"类的"init"方法处也设置断点。
- 完成断点设置后,点击IDEA工具栏上的"Debug"(调试)按钮开始调试。
- 注意事项:
- 如果本地编译的class文件已经是最新编译的,直接点击"Debug"按钮可能不会进入调试状态。这种情况下,需要修改代码,比如修改
xxx
类的属性,以确保有新的class文件生成,然后再次尝试点击"Debug"按钮。