返回

对象拷贝工具库

对于开发而言,由于分层架构设计,需要频繁使用到对象转换功能,如果是手写 Get/Set, 那将是非常枯燥和低效的,下面就介绍几种工具库可以很方便实现该功能。

markdown 写目录时,注意锚点需要全小写,否则点击无法跳转

Spring BeanUtils

Spring BeanUtils的实现原理也比较简答,就是通过Java的Introspector获取到两个类的PropertyDescriptor,对比两个属性具有相同的名字和类型,

如果是,则进行赋值(通过ReadMethod获取值,通过WriteMethod赋值),否则忽略。

为了提高性能Spring对BeanInfo和PropertyDescriptor进行了缓存。

使用方法: BeanUtils.copyProperties(sourceVO, targetVO)

Apache BeanUtils

Apache的BeanUtils的实现原理跟Spring的BeanUtils一样,也是主要通过Java的Introspector机制获取到类的属性来进行赋值操作,对BeanInfo和PropertyDescriptor同样有缓存,但是Apache BeanUtils加了一些不那么使用的特性(包括支持Map类型、支持自定义的DynaBean类型、支持属性名的表达式等等)在里面,使得性能相对Spring的BeanUtils来说有所下降。

使用方法: BeanUtils.copyProperties(targetVO, sourceVO)

由于性能问题,阿里的Java规范是不建议使用的。

BeanCopier

BeanCopier的实现原理跟BeanUtils截然不同,它不是利用反射对属性进行赋值,而是直接使用cglib来生成带有的get/set方法的class类,然后执行。由于是直接生成字节码执行,所以BeanCopier的性能接近手写。

BeanCopier性能确实很高,但BeanCopier只会拷贝名称和类型都相同的属性,而且如果一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。

Dozer

document 有支持同名隐式映射,支持基本类型互相转换,支持显示指定映射关系,支持exclude字段,支持递归匹配映射,支持深度匹配,支持Date to String的date-formate,支持自定义转换Converter,支持一次mapping定义多处使用,支持EventListener事件监听等等。不仅如此,Dozer在使用方式上,除了支持API,还支持XML和注解。

使用方法: TargetVO map = dozerMapper.map(sourceVO, TargetVO.class);

Dozer功能强大,但底层还是用反射那套,所以在性能测试中它的表现一般,仅次于Apache的BeanUtils。

Mapstruct

document 通过注解的方式进行对象配置,在编译完成后生成实体转换代码, 相当于帮我们手写了 Get/Set, 生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。

缺点:最近在使用发现,对于较多不一致属性进行映射特别麻烦,经常编译失败,对使用语法有强校验。所以花费时间更多,还不如手写。

Orika

document 不同于 Mapstruct 在编译器生成实体代码,进行转换, Orika底层使用Javassist生成字节码,在做映射过程中生成mapper的源码和字节码, 运行效率很高的。推荐使用。

参考1