目录
一、mapstruct简介
二、mapstruct与其他映射框架对比
三、mapstruct底层原理解析
1、Java动态编译
2、mapstruct包分析
?3、使用方式
4、实现原理
四、小结
参考
一、mapstruct简介
mapstruct是一种实体类映射框架能够通过Java注解将一个实体类的属性安全地赋值给另一个实体类。有了mapstruct只需要定义一个映射器接口声明需要映射的方法在编译过程中mapstruct会自动生成该接口的实现类实现将源对象映射到目标对象的效果。
二、mapstruct与其他映射框架对比
实体类映射框架大致有两种一种是运行期通过java反射机制动态映射另一种是编译期动态生成getter/setter在运行期直接调用框架编译好的class类实现实体映射。
由于mapstruct映射是在编译期间实现的因此相比运行期的映射框架有以下几个优点
安全性高。因为是编译期就实现源对象到目标对象的映射 如果编译器能够通过运行期就不会报错。速度快。速度快指的是运行期间直接调用实现类的方法不会在运行期间使用反射进行转化。 三、mapstruct底层原理解析
mapstruct是基于JSR 269实现的JSR 269是JDK引进的一种规范。有了它能够实现在编译期处理注解并且读取、修改和添加抽象语法树中的内容。JSR 269使用Annotation Processor在编译期间处理注解Annotation Processor相当于编译器的一种插件因此又称为插入式注解处理。想要实现JSR 269主要有以下几个步骤
继承AbstractProcessor类并且重写process方法在process方法中实现自己的注解处理逻辑。在META-INF/services目录下创建javax.annotation.processing.Processor文件注册自己实现的Annotation Processor 1、Java动态编译
Java程序编译一般经历以下流程
图1 Java程序编译流程
上图中Java源码到class文件的过程其实是一个比较复杂的过程。其中的经过可以用下图描述
图2 mapstruct编译过程
上图的流程可以概括为下面几个步骤
生成抽象语法树。Java编译器对Java源码进行编译生成抽象语法树Abstract Syntax TreeAST。调用实现了JSR 269 API的程序。只要程序实现了JSR 269 API就会在编译期间调用实现的注解处理器。修改抽象语法树。在实现JSR 269 API的程序中可以修改抽象语法树插入自己的实现逻辑。生成字节码。修改完抽象语法树后Java编译器会生成修改后的抽象语法树对应的字节码文件件。 2、mapstruct包分析
mapstruct主要有两个包
org.mapstruct:mapstruct包含了映射相关的注解如Mapper、Mapping等。org.mapstruct:mapstruct-processor包含了注解处理器。用于处理注解相关的逻辑如MappingProcessor等。
两个包大致包含的类如下图所示
图3org.mapstruct:mapstruct结构
图4org.mapstruct:mapstruct-processor结构
3、使用方式
mapstruct的用法很简单假设我们有两个实体类UserDto和UserVo类定义如下
public class UserDTO { private String name; private int age; private Date birthday; private int gender; private String idCard;}public class UserVo { private String userName; private int age; private Date birthday; private int gender; private String idCard;}
然后需要定义一个用例映射的接口接口如下
Mapperpublic interface UserConverter { Mappings({ Mapping(source name, target userName) }) UserVo userDtoToVo(UserDto userDto);}
在UserConverter接口上添加Mapper注解在编译的时候mapstruct自动会生成一个UserConverter的实现类实现userDtoToVo方法。userDtoToVo方法上的Mappings主要用于特殊映射比如上述的UserDto中的name想要映射成userName则通过Mappings告诉mapstruct将source中的name映射成target中的userName字段。
通过mapstruct处理后自动生成UserConverterImpl类类实现代码如下所示
Override public UserVo userDtoToVo(UserDto userDto) { if ( userDto null ) { return null; } UserVo userVo new UserVo(); if ( userDto.getName() ! null ) { userVo.setUserName( userDto.getName() ); } userVo.setAge( userDto.getAge() ); if ( userDto.getBirthday() ! null ) { userVo.setBirthday( userDto.getBirthday() ); } if ( userDto.getGender() ! null ) { userVo.setGender( Integer.parseInt( userDto.getGender() ) ); } if ( userDto.getIdCard() ! null ) { userVo.setIdCard( userDto.getIdCard() ); } return userVo; } 4、实现原理
想要了解原理可以从mapstruct的源码入手。上文介绍过mapstruct主要有两个jar包通过根据JSR 269可以知道MappingProcessor就是mapstruct的入口。com.sun.tools.javac.main.JavaCompiler#compile方法的有段代码在编译的时候会调用到MappingProcessor。compile代码如图5所示
图5 compile方法
MappingProcessor的process方法具体代码如下所示
SupportedAnnotationTypes({org.mapstruct.Mapper})SupportedOptions({mapstruct.suppressGeneratorTimestamp, mapstruct.suppressGeneratorVersionInfoComment, mapstruct.unmappedTargetPolicy, mapstruct.defaultComponentModel})public class MappingProcessor extends AbstractProcessor { public boolean process(Set
还没有评论,来说两句吧...