常见或常用的几种Bean属性复制工具
Apache.BeanUtilsApache.PropertyUtilSpring.BeanUtilsCglib.BeanCopierMapStructEZMorph使用场景:Dto与Entity转换
普通属性复制个别属性过滤属性类型转换数组或集合拷贝测试在两个简单的Bean之间转换的耗时,执行次数分别为10、100、1k、10k、100k,时间单位为ms。
org.apache.commons.beanutils
通过内省(Introspector)获取源类型的属性信息判断源类型的属性是否可读及目标类型的属性是否可写 可读 有getter方法 可写 有setter方法 进行复制 获取属性名获取属性类型进行属性值转类型[自带类型转换器,提供注册自定义转换器接口]赋值执行过程
获取工具实例,调用属性复制方法 获取实例方法 实例获取的函数是同步的,因为ContextClassLoader的不同,每个线程都会创建一个实例 属性复制函数:先是空值的判断,然后通过Java内省机制获取属性描述,判断属性是否可读/可写,然后通过反射赋值发现在初始化过程中,BeanUtils实例的获取是“假单例”模式,每个线程拥有一个BeanUtils实例,所以每个线程每次初始化都消耗资源。
org.apache.comons.beanutils
使用内省,操作getter/setter方法。基本流程同Apache.BeanUtils
区别
BeanUtils支持属性类型转换,而PropertyUtils不支持,若有同名不同类型的属性,则会报错。
BeanUtils自带类型转换器,支持如下类型转换:
java.lang.BigDecimaljava.lang.BigIntegerboolean and java.lang.Booleanbyte and java.lang.Bytechar and java.lang.Characterjava.lang.Classdouble and java.lang.Doublefloat and java.lang.Floatint and java.lang.Integerlong and java.lang.Longshort and java.lang.Shortjava.lang.Stringjava.sql.Datejava.sql.Timejava.sql.Timestamporg.springframework.beans.BeanUtils
Spring的BeanUtils也是通过java内省机制获取getter/setter,然后通过反射调用从而实现属性复制,但区别于Apache的BeanUtils,Spring的BeanUtils为单例模式,不需要重复创建。同时,Spring.BeanUtils支持忽略属性。
net.sf.cglib.beans
使用动态代理,生成字节码类,再通过Java反射成Class,调用其copy方法。
执行过程
创建BeanCopier
[使用了缓存,该过程也消耗资源,建议全局只初始化一次]
通过字节码生成了两个类
KeyFactoryBeanCopier调用copy方法。 (支持自定义类型转换器)
【有convert的情况】
【无convert的情况】
生成的BeanCopier里面直接使用Bean的setter/getter
org.mapstrcut.*
http://mapstruct.org/ 支持XML配置和注解配置
使用示例
自定义Mapper类 编译生成实现类 Bean复制性能感人,不做深究。
也是通过反射
根据属性复制工具的功能维度对工具进行分析,对比如下:
Apache.BeanUtils Apache.PropertyUtil Spring.BeanUtils Cglib.BeanCopier MapStruct EZMorph根据不同工具的性能及功能维度,个人建议当对象转换操作较少或者应用对性能要求较高时,尽量不采用工具,而是手写getter/setter;在不考虑性能的情况下,普通的对象转换可以使用Cglib.BeanCopier,复杂的对象转换使用MapStruct。