01 引言
日常开发中,我们经常会遇到对象转化的问题。尤其阿里提出了DTO、BO、VO、PO的概念之后,对于转化的场景更多。
转化的工具也不少,BeanUtils、MapStruct、Orika等工具层出不穷,每个人或者团队的选择也大不相同。
02 三大流派
Java 生态里"对象转对象"这件事大致分为桑哥流派。
2.1 手写派
new一个对象,然后setter挨个赋值。这个是最简单,最常用的手段。但是字段多的话,就会角色很繁琐。
UserDTOdto=newUserDTO();dto.setId(user.getId());dto.setName(user.getName());dto.setAge(user.getAge());dto.setEmail(user.getEmail());dto.setPhone(user.getPhone());dto.setCreateTime(user.getCreateTime());// ... 30 行 setterreturndto;但是,AI时代,AI提示工具会帮我们直接联想关联,也省了不少功夫,但是代码量不会变。
优缺点:
- 优点:性能拉满,可读性尚可。
- 缺点:字段超过 10 个就开始怀疑人生,字段名修改需要联动修改。
2.2 反射派
反射的工具类代表:Spring BeanUtils、Apache Commons BeanUtils、Hutool BeanUtil。
BeanUtils.copyProperties(source,target);使用工具类是最省事情的,但是不同的工具参数以及最终的结构都少有差异。如果字段的类型不一致,还可能出现转化失败。最关键的,性能也是最差的。
优缺点:
- 优点:一行代码搞定,懒人福音。
- 缺点:运行时反射,性能是硬伤;还不做类型检查,
int字段和String字段同名也能给你"成功"转过去——数据错了你都不知道怎么错的。
2.3 编译期生成派
代表:MapStruct、MapStruct Plus。
就是在在你javac编译的时候,APT(注解处理器)自动生成转换代码,运行时压根没反射。运行效果同Setter方法。
这也是今天我们要介绍的重点工具。
03 MapStruct
3.1 简介
MapStruct 是 Java 圈做 Bean 映射的事实标准,Apache-2.0 协议,GitHub 上7.7k颗 star,背后有一整个组织在维护。最新稳定版1.6.3。
官网:https://mapstruct.org
GitHub地址:https://github.com/mapstruct/mapstruct
3.2 使用
使用也是非常简单。
Maven依赖
...<properties><org.mapstruct.version>1.6.3</org.mapstruct.version></properties>...<dependencies><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct</artifactId><version>${org.mapstruct.version}</version></dependency></dependencies>...<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.version}</version></path></annotationProcessorPaths></configuration></plugin></plugins></build>...定义转化接口
@Mapper(componentModel=MappingConstants.ComponentModel.SPRING)publicinterfaceUserMapper{UserVOuserDtoToVO(UserDTOuserDto);}这里使用Spring实例模式,定义的方法上可以通过@Mapping(target = "a", source = "b")定制处理不同的字段的映射。
maven 配置annotation processor,编译的时候它就给你生成一个UserMapperImpl.java,里面全是规规矩矩的target.setXxx(source.getXxx())。
调用
3.3 缺点
这玩意儿最大的问题:烦。
每对类型转换,你都要写一个@Mapper接口。如果你项目里 50 个 DTO,那就是 50 个 Converter 类。直接类爆炸!
04 MapStruct Plus
国产"外挂"来了,顾名思义就是MapStruct的加强版。
4.1 简介
Mapstruct Plus 是 Mapstruct 的增强工具,在 Mapstruct 的基础上,实现了自动生成 Mapper 接口的功能,并强化了部分功能,使 Java 类型转换更加便捷、优雅。
可能是最简单最强大的Java Bean转换工具。
Mapstruct Plus所解决的痛点正式取消了定义转化的接口,取而代之的是注解。
官网地址:https://www.mapstruct.plus/
GitHub地址:https://github.com/linpeilie/mapstruct-plus
4.2 使用
Maven依赖
<properties><mapstruct-plus.version>latest version</mapstruct-plus.version></properties><dependencies><dependency><groupId>io.github.linpeilie</groupId><artifactId>mapstruct-plus-spring-boot-starter</artifactId><version>${mapstruct-plus.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><annotationProcessorPaths><path><groupId>io.github.linpeilie</groupId><artifactId>mapstruct-plus-processor</artifactId><version>${mapstruct-plus.version}</version></path></annotationProcessorPaths></configuration></plugin></plugins></build>定义实体
@Data@AllArgsConstructor@NoArgsConstructor@AutoMapper(target=UserVO.class)publicclassUserDTO{/** 用户ID */privateIntegerid;/** 用户名 */privateStringname;/** 出生日期 */privateDatebirthday;/** 电话号码 */privateStringphone;}这里面最关键注解是@AutoMapper(target = UserVO.class)
调用
就这么简单,一个注解就是实现相互的转化。我们看看为什么,原来是编译的时候,生成相互转化的实现类。
4.3 优点
- 零接口、零模板——这是核心卖点,CRUD 业务写起来像飞一样。
- 底层依然是 MapStruct——编译期生成、零反射、类型安全,全部继承。
- 双向转换自动生成——A→B 和 B→A 都给你生成好,不用写两份。
- 中英文双文档——这点对国内开发者是真香,作者中文母语,文档写得比 MapStruct 官方还接地气
4.4 缺点
既然是其他工具的增强类,必然依赖者MapStruct。
- 社区体量小——Issue/Discussion 数量远不如 MapStruct,遇冷门问题得自己扒源码。
- 版本耦合底层——MapStruct 大版本升级,Plus 得跟着更,存在一定不确定性。
- 复杂自定义场景灵活性略弱——比如
expression、Decorator、SPI 这些高级玩法,Plus 还在追赶原版
05 Bean 转换工具合集
整理一下常用的转化工具:
5.1 编译期派
- MapStruct:业界标杆,权威。
- MapStruct Plus:MapStruct 的"懒人版",国内首选。
- Selma / JMapper:历史方案,已不活跃,不推荐。
5.2 反射派
- Spring BeanUtils:Spring 自带,单测和小工具用用就好,线上大对象别上。
- Apache Commons BeanUtils:慢到能让你怀疑人生,不推荐。
- Hutool BeanUtil:国内工具包,国产项目首选,但本质还是反射。
- Dozer:XML 配置映射,曾经火过,现在基本凉凉。
- Orika:基于字节码生成,比反射快,比编译期慢,不上不下。
5.3 字节码派
- Cglib BeanCopier:阿里、美团内部爱用,首次创建后缓存,性能接近手写。
- ByteBuddy:现代化方案,Spring 自己也用。
06 小结
选工具不是选最强的,是选最适合的。每一种工具都存在其必要的使用场景,复杂业务永远离不开手写的作为兜底。