CarDTO entity = JSON.parseObject(JSON.toJSONString(carDO), CarDTO.class);
这种方案因为通过生成中间json格式字符串,然后再转化成目标对象,性能非常差,同时因为中间会生成json格式字符串,如果转化过多,gc会非常频繁,同时针对复杂场景支持能力不足,基本很少用。
2 BeanUtil类
BeanUtil.copyProperties()结合手写get、set,对于简单的转换直接使用BeanUtil,复杂的转换自己手工写get、set。该方案的痛点就在于代码编写效率低、冗余繁杂还略显丑陋,并且BeanUtil因为使用了反射invoke去赋值性能不高。
只能适合bean数量较少、内容不多、转换不频繁的场景。
apache.BeanUtils
org.apache.commons.beanutils.BeanUtils.copyProperties(do, entity);
这种方案因为用到反射的原因,同时本身设计问题,性能比较差。集团开发规约明确规定禁止使用。
spring.BeanUtils
org.springframework.beans.BeanUtils.copyProperties(do, entity);
这种方案针对apache的BeanUtils做了很多优化,整体性能提升不少,不过还是使用反射实现比不上原生代码处理,其次针对复杂场景支持能力不足。
3 beanCopier
BeanCopier copier = BeanCopier.create(CarDO.class, CarDTO.class, false);
copier.copy(do, dto, null);
这种方案动态生成一个要代理类的子类,其实就是通过字节码方式转换成性能最好的get和set方式,重要的开销在创建BeanCopier,整体性能接近原生代码处理,比BeanUtils要好很多,尤其在数据量很大时,但是针对复杂场景支持能力不足。
4 各种Mapping框架
分类
Object Mapping 技术从大的角度来说分为两类,一类是运行期转换,另一类则是编译期转换:
-
运行期反射调用 set/get 或者是直接对成员变量赋值。这种方式通过invoke执行赋值,实现时一般会采用beanutil, Javassist等开源库。运行期对象转换的代表主要是Dozer和ModelMaper。
-
编译期动态生成 set/get 代码的class文件,在运行时直接调用该class的 set/get 方法。该方式实际上仍会存在 set/get 代码,只是不需要开发人员自己写了。这类的