一、介绍
1、功能介绍2、不同方法与性能对比 二、转换案例
1、源VO和目标VO2、get/set3、Json2Json4、Spring copyProperties✨5、BeanCopier6、MapStruct✨✨ 一、介绍 1、功能介绍
在 Java 系统工程开发过程中,都会有各个层之间的对象转换,比如 VO、DTO、PO、VO 等,而如果都是手动get、set又太浪费时间,还可能操作错误,所以选择一个自动化工具会更加方便
2、不同方法与性能对比目前用于对象属性转换有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,的技术手段实现的,所以也会有相应的性能损耗
二、转换案例 1、源VO和目标VO
//源类@Data@AllArgsConstructor@NoArgsConstructor@Accessors(chain = true)public class SourceVO { private String name; private String password; private Integer age;}//目标类@Data@Accessors(chain = true)public class TargetVO { private String name; private String password; private Integer age;}
2、get/set这种方式也是日常使用的最多的,性能十分优秀,但是操作起来有点麻烦。多个get/set可以通过 Shift+Alt 选中所有属性,Shift+Tab 归并到一列,接下来在使用 Alt 选中这一列,批量操作粘贴 targetVO.set 以及快捷键大写属性首字母,最后切换到结尾补充括号和分号,最终格式化一下就可以了
3、Json2Json把对象转JSON串,再把JSON转另外一个对象,这种方式性能不是很高
public class ObjectConversion { public static
public class Test { public static void main(String[] args){ SourceVO sourceVO = new SourceVO("shawn","123456",18); TargetVO targetVO = ObjectConversion.copy(sourceVO, TargetVO.class); System.out.println(targetVO); }}
4、Spring copyProperties✨这个方法是反射的属性拷贝,Spring 提供的 copyProperties 要比 Apache 好用的多,性能和操作都比较好,这个包是org.springframework.beans.BeanUtils
另外这里考虑到属性不同的字段的拷贝,还额外创建了一个回调函数进行映射处理
//回调函数定义,这里用了java8特性函数式接口@FunctionalInterfacepublic interface BeanCopyUtilCallBack { void callBack(S t, T s);}
public class BeanCopyUtil extends BeanUtils { public static List sources, Supplier List sources, Supplier callBack) { List
这里的回调函数可以使用Enum枚举进行规范化,最终进行测试,成功拷贝
ublic class Test { public static void main(String[] args){ // 单个拷贝 SourceVO sourceBean = new SourceVO("shawn", "123456", 18); TargetVO targetBean = new TargetVO(); BeanUtils.copyProperties(sourceBean,targetBean); System.out.println(targetBean); // 列表拷贝 List
Cglib BeanCopier 的原理与Beanutils 原理不太一样,其主要使用 字节码技术动态生成一个代理类,代理类实现get 和 set方法。生成代理类过程存在一定开销,但是一旦生成,我们可以缓存起来重复使用,所有 Cglib 性能相比Beanutils 性能比较好整体性能不错,使用也不复杂
//工具类public class WrapperBeanCopier { public static
public class Test { public static void main(String[] args){ // 单个拷贝 SourceVO sourceVO = new SourceVO("shawn", "123456", 18); TargetVO targetVO = WrapperBeanCopier.copyProperties(sourceVO, TargetVO.class); System.out.println(targetVO); // 列表拷贝 List
如果要自定义转换,可以使用new Converter(),一旦我们自己打开使用转换器,所有属性复制都需要我们自己来了,否则会导致无法复制。另外这里需要注意的是拷贝对象要去除@Accessors(chain = true)注解,因为该注解会将 setter 方法的返回值由 void 修改为当前对象。这导致 setter 的方法签名改变,最终导致 BeanCopier 无法识别现有的 setter 方法
6、MapStruct✨✨官网文档地址:https://github.com/mapstruct/mapstruct
MapStruct是一款基于Java注解的对象属性映射工具,在Github上已经有4.5K+Star。使用的时候我们只要在接口中定义好对象属性映射规则,它就能自动生成映射实现类,不使用反射,性能优秀,能实现各种复杂映射。(强烈推荐)
首先导入Maven依赖
创建Bean对象
@Data@AllArgsConstructor@NoArgsConstructor@Accessors(chain = true)public class SourceVO { private String name; private String password; private Integer age; private Date birthday;}@Data@AllArgsConstructor@NoArgsConstructor@Accessors(chain = true)public class TargetVO { private String name; private String pwd; private Integer age; private String birthday;}
编写Mapper文件,实现同名同类型属性、不同名称属性、不同类型属性的映射
@Mapperpublic interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); @Mapping(target = "pwd", source = "password") @Mapping(source = "birthday",target = "birthday", dateFormat = "yyyy-MM-dd") TargetVO getTargetVO(SourceVO sourceVO);}
最后直接通过接口中的INSTANCE实例调用转换方法
public class Test { public static void main(String[] args){ SourceVO sourceVO = new SourceVO("shawn", "123456", 18, new Date()); TargetVO targetVO = UserMapper.INSTANCE.getTargetVO(sourceVO); System.out.println(targetVO); }}
其实MapStruct的实现原理很简单,就是根据我们在Mapper接口中使用的@Mapper和@Mapping等注解,在运行时生成接口的实现类,我们可以打开项目的target目录查看
初次之外,MapStruct使用有:
基本映射、集合映射、子对象映射、合并映射使用依赖注入、使用常量/默认值/表达式、映射前后自定义、处理映射异常等
详情可参考:
https://blog.csdn.net/zhenghongcs/article/details/121349361
https://mapstruct.org/documentation/stable/reference/html/
参考文章
https://mp.weixin.qq.com/s/_QJa5RSxvPBsqXo8yS5-pg