几种Bean映射工具介绍
一、介绍
1、功能介绍
在 Java 系统工程开发过程中,都会有各个层之间的对象转换,比如 VO、DTO、PO、VO 等,而如果都是手动get、set
又太浪费时间,还可能操作错误,所以选择一个自动化工具会更加方便;同时在工作也常常遇到将java的Bean对象转化为Map,或者将Map转为Bean对象的情况。
2、Bean互转不同方法与性能对比
目前用于对象属性转换有12种,包括普通的get/set、json2Json、Apache属性拷贝、Spring属性拷贝、bean-mapping、bean-mapping-asm、BeanCopier、Orika、Dozer、ModelMapper、JMapper、MapStruct
- Spring 提供的
BeanUtils.copyProperties
是大家代码里最常出现的工具类,注意不是Apache
包下 - 手动
get、set
性能是最好的,另外MapStruct
性能和操作也很方便,因为它本身就是在编译期生成get、set
代码,和我们写get、set
一样 - 其他一些组件包主要基于
AOP
、ASM
、CGlib
,的技术手段实现的,所以也会有相应的性能损耗
3、Bean/Map互转
工作常常遇到将java的Bean对象转化为Map,或者将Map转为Bean对象,常见手段有以下几种
- 通过json工具,将Bean转json,再将json转Map(效率低)
- jdk的反射,获取类的属性,进行转化(比较麻烦,书写代码比较多)
- 通过工具类
BeanMap
来完成(效率高,底层也是基于反射,不过做了些优化,比如缓存等手段 ,推荐) - 通过
Apache的BeanUtils
来完成(bean转化map是Map<String, String>类型)
二、Bean转换案例
1、源VO和目标VO
1 | //源类 |
2、get/set
这种方式也是日常使用的最多的,性能十分优秀,但是操作起来有点麻烦。多个get/set可以通过 Shift+Alt 选中所有属性,Shift+Tab 归并到一列,接下来在使用 Alt 选中这一列,批量操作粘贴 targetVO.set
以及快捷键大写属性首字母,最后切换到结尾补充括号和分号,最终格式化一下就可以了
3、Json2Json
把对象转JSON串,再把JSON转另外一个对象,这种方式性能不是很高
1 | /** |
1 | public class Test { |
4、Spring copyProperties✨
这个方法是反射的属性拷贝,Spring 提供的 copyProperties 要比 Apache 好用的多,性能和操作都比较好,这个包是org.springframework.beans.BeanUtils
另外这里考虑到属性不同的字段的拷贝,还额外创建了一个回调函数进行映射处理
1 | //回调函数定义,这里用了java8特性函数式接口 |
1 | /** |
这里的回调函数可以使用Enum枚举进行规范化,最终进行测试,成功拷贝
1 | ublic class Test { |
另一种方法进行转换,常用
1 | public class JPAUtils { |
1 | public class BeanDtoVoUtils<V, E> { |
5、BeanCopier
Cglib BeanCopier 的原理与Beanutils 原理不太一样,其主要使用 字节码技术动态生成一个代理类,代理类实现get 和 set方法。生成代理类过程存在一定开销,但是一旦生成,我们可以缓存起来重复使用,所有 Cglib 性能相比Beanutils 性能比较好整体性能不错,使用也不复杂
1 | //工具类 |
1 | public class Test { |
如果要自定义转换,可以使用new Converter()
,一旦我们自己打开使用转换器,所有属性复制都需要我们自己来了,否则会导致无法复制。另外这里需要注意的是拷贝对象要去除@Accessors(chain = true)
注解,因为该注解会将 setter
方法的返回值由 void
修改为当前对象。这导致 setter
的方法签名改变,最终导致 BeanCopier
无法识别现有的 setter
方法
6、MapStruct✨✨
MapStruct是一款基于Java注解的对象属性映射工具,在Github上已经有4.5K+Star。使用的时候我们只要在接口中定义好对象属性映射规则,它就能自动生成映射实现类,不使用反射,性能优秀,能实现各种复杂映射。(强烈推荐)
首先导入Maven依赖
1 | <dependency> |
创建Bean对象
1 |
|
编写Mapper文件,实现同名同类型属性、不同名称属性、不同类型属性的映射
1 |
|
最后直接通过接口中的INSTANCE
实例调用转换方法
1 | public class Test { |
其实MapStruct的实现原理很简单,就是根据我们在Mapper接口中使用的@Mapper
和@Mapping
等注解,在运行时生成接口的实现类,我们可以打开项目的target
目录查看
初次之外,MapStruct使用有:
- 基本映射、集合映射、子对象映射、合并映射
- 使用依赖注入、使用常量/默认值/表达式、映射前后自定义、处理映射异常等
详情可参考:
https://blog.csdn.net/zhenghongcs/article/details/121349361
https://mapstruct.org/documentation/stable/reference/html/
三、Bean/Map互转
1、JSON 工具互转
1 | public class BeanMapUtilByJson { |
2、JDK反射互转
这种操作是利用 java 原生提供的反射特性来实现互转
1 | public class BeanMapUtilByReflect { |
3、BeanMap转换(推荐)
BeanMap是org.springframework.cglib.beans.BeanMap,在springcore中
1 | public class BeanMapTool { |
4、BeanUtils互转
首先导入依赖
1 | <dependency> |
工具类
1 | public class BeanUtilsTool { |
5、实战技巧
注意反射方法进行的时候一定要有无参构造,否则会报错找不到该方法
1 |
|
参考文章
https://mp.weixin.qq.com/s/_QJa5RSxvPBsqXo8yS5-pg