Java对象拷贝的方式
原因:
在写我的个人博客系统的时候碰到了需要对象转换的情况:
- 如图这是一个文章信息的PO对象,与数据库表的各个字段是一一对应的
- 这是一个文章列表信息的VO对象,大部分字段都是需要从查询出来的PO里面获取的,而此时我们就需要进行对象类型的转换了
对象拷贝的常见方式:
通常以下几种是比较常用的对象拷贝方式:
- 直接调用两种对象的getter/setter方法
- Apache.BeanUtils.copyProperties()
- SpringFramework内置的copyProperties()
- mapstruct框架----一个专门为Javabean对象映射转换而生的框架
这是常见的对象转换方式的性能对比图了
性能分析对比:
1.get\set
直接调用对象提供的get/set方法进行对象类型转换,自己手动一个个get出源对象的属性,然后调用另一个对象的set方法去注入即可,几乎没有脑力劳动,全程可控,从性能对比图中也可以看出来,这种方式的性能是最好的,并且出了对象复制出现bug直接开个debug模式打个断点就能找到源头。
但是毫无疑问,这种方式是代码量最大的,大量重复的get和set方法在项目内部需要占用的太多空间了,比较影响观感,而且耦合程度很高,一旦实体类的成员变量发生改变,就得对应修改拷贝方法中的get/set方法,维护起来也不容易
评价:性能之王,但是代码量也大,代码间耦合程度高
2.Apache.BeanUtils.copyProperties()
这个方法基本上现在没人会选用了,一个是bug多容易踩坑,二一个是基于反射实现的同时,在高并发且数据量大的情况下表现为性能急剧下降,如果你的项目有在使用该方法进行对象拷贝,请选择其他工具类里面的BeanUtils进行替换
评价:大数据量性能下降严重,会拖垮整个系统,bug多容易踩坑,强烈不推荐使用
3.SpringFrameWork下的BeanUtils.copyProperties()
同样基于反射实现的,但是这个性能吊打上面那个方法,而且是spring官方维护的,简单易用,文档丰富(愿意去找英文文档看就很详细),bug少,按照文档说明规范使用基本上是没有坑的,有坑的话网上基本上也有解决方案,不需要额外导包,spring内置好了
评价:性能稳定,bug少,简单易用不需要额外导包,推荐使用
4.MapStruct
这也是我个人目前正在使用的拷贝方式,性能上仅次于set/get(没得办法,毕竟这个框架实际上也就是在编译器给你把对象映射的get和set方法一键生成调用了而已,但是性能也已经很不错了)
评价:推荐使用,支持属性映射时候的一些定制化操作,比如两种对象类型的不同日期类型成员变量间的日期格式转换,源属性名与目标属性名存在不同,定制化操作是使用注解来完成的,非常方便
mapstruct框架介绍:
mapstruct官方的GitHub仓库地址:mapstruct.io
- Maven方式导包如下:
-
<dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency>
建立一个convert包,里面的类专门用于对象转换,如上图所示,这是我写的不同文章对象之间的转换类,在调用的时候直接获取到实例对象INSTANCE调用方法就可以直接进行对象转换了
下面是使用示例:
ArticleListVO articleListVO2 = ArticleConvert.INSTANCE.POToVo(articlePO);
只需要这样简单的一句话就能将PO对象转成VO对象了
如果源属性和目标属性名称不同,则一定需要在convert类中对应的转换方法上加上@Mapping注解,简单类型不同一般无需专门处理,在编译期mapstruct会帮你做好类型转换,这点你无需担心
当然,这个框架也并不是十全十美的
它目前还是有些小坑的,比如说你转换对象的属性的类型或者名称发生了改变,它在重新编译的时候并不会帮你修正过来,你必须手动清除掉原来生成的target文件,比如maven的clean或者手动删除target文件夹,否则你再次编译的时候就会报错,这点是值得注意的,相信对于以后应该也能支持即时编译,这个框架还是很好用的