七种对象复制工具类,阿粉该 Pick 谁?

本文介绍了七种Java对象复制工具类,包括Apache BeanUtils、Spring BeanUtils、Cglib BeanCopier、Dozer、orika和MapStruct,讨论了它们的特性、优缺点以及性能。其中,Apache BeanUtils因性能不佳不推荐使用,Spring BeanUtils和Cglib BeanCopier提供了基本的属性复制,而Dozer和orika提供了更高级的功能如类型转换和字段映射,MapStruct则在编译期间生成代码以提高性能。
摘要由CSDN通过智能技术生成

每天早上七点三十,准时推送干货

日常编程中,我们会经常会碰到对象属性复制的场景,就比如下面这样一个常见的三层 MVC 架构。

当我们在上面的架构下编程时,我们通常需要经历对象转化,比如业务请求流程经历三层机构后需要把 DTO 转为DO然后在数据库中保存。

当需要从数据查询数据页面展示时,查询数据经过三层架构将会从 DO  转为 DTO,最后再转为 VO,然后在页面中展示。

当业务简单的时候,我们手写代码,通过 getter/setter复制对象属性,十分简单。但是一旦业务变的复杂,对象属性变得很多,那么手写代码就会成为程序员的噩梦。

不但手写十分繁琐,非常耗时间,并且还可能容易出错。

阿粉之前就经历过一个项目,一个对象中大概有四五十个字段属性,那时候阿粉还刚入门,什么都不太懂,写了半天 getter/setter复制对象属性。

话外音:一个对象属性这么多,显然是不太合理的,我们设计过程应该将其拆分。

直到后来,阿粉了解到了对象属性复制工具类,使用之后,发现是真香,再也不用手写代码。再后来,碰到越来越多工具类,虽然核心功能都是一样的,但是还是存在很多差异。新手看到可能会一脸懵逼,不知道如何选择。

所以阿粉今天这篇介绍一下市面上常用的工具类:

  • Apache BeanUtils

  • Spring BeanUtils

  • Cglib BeanCopier

  • Dozer

  • orika

  • MapStruct

工具类特性

在介绍这些工具类之前,我们来看下一个好用的属性复制工具类,需要有哪些特性:

  • 基本属性复制,这个是基本功能

  • 不同类型的属性赋值,比如基本类型与其包装类型等

  • 不同字段名属性赋值,当然字段名应该尽量保持一致,但是实际业务中,由于不同开发人员,或者笔误拼错单词,这些原因都可能导致会字段名不一致的情况

  • 浅拷贝/深拷贝,浅拷贝会引用同一对象,如果稍微不慎,同时改动对象,就会踩到意想不到的坑

下面我们开始介绍工具类。

画外音:公号内回复「20200822」获取源码

Apache BeanUtils

首先介绍是第一位应该是 Java 领域属性复制的最有名的工具类「Apache BeanUtils」,这个工具类想必很多人或多或少用过或则见过。

没用过也没关系,我们来展示这个类的用法,用法非常简单。

首先我们引入依赖,这里使用最新版本:

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.4</version>
</dependency>

假设我们项目中有如下类:

此时我们需要完成 DTO 对象转化到 DO 对象,我们只需要简单调用BeanUtils#copyProperties 方法就可以完成对象属性的复制。

StudentDTO studentDTO = new StudentDTO();
studentDTO.setName("阿粉");
studentDTO.setAge(18);
studentDTO.setNo("6666");

List<String> subjects = new ArrayList<>();
subjects.add("math");
subjects.add("english");
studentDTO.setSubjects(subjects);
studentDTO.setCourse(new Course("CS-1"));
studentDTO.setCreateDate("2020-08-08");

StudentDO studentDO = new StudentDO();

BeanUtils.copyProperties(studentDO, studentDTO);

不过,上面的代码如果你这么写,我们会碰到第一个问题,BeanUtils 默认不支持 String转为 Date 类型。

为了解决这个问题,我们需要自己构造一个 Converter 转换类,然后使用 ConvertUtils注册,使用方法如下:

ConvertUtils.register(new Converter() {
    @SneakyThrows
    @Override
    public <Date> Date convert(Class<Date> type, Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof String) {
            String str = (String) value;
            return (Date) DateUtils.parseDate(str, "yyyy-MM-dd");
        }
        return null;


    }
}, Date.class);

此时,我们观察 studentDOstudentDTO对象属性值:

从上面的图我们可以得出BeanUtils一些结论:

  • 普通字段名不一致的属性无法被复制

  • 嵌套对象字段,将会与源对象使用同一对象,即使用浅拷贝

  • 类型不一致的字段,将会进行默认类型转化。

虽然 BeanUtils 使用起来很方便,不过其底层源码为了追求完美,加了过多的包装,使用了很多反射,做了很多校验,所以导致性能较差,所以并阿里巴巴开发手册上强制规定避免使用 Apache BeanUtils

image-20200818222213879

Spring BeanUtils

Spring 属性复制工具类类名与 Apache 一样,基本用法也差不多。我先来看下 Spring BeanUtils 基本用法。

同样,我们先引入依赖,从名字我们可以看出,BeanUtils 位于 Spring-Beans 模块,这里我们依然使用最新模块。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

这里我们使用 DTO 与 DO 复用上面的例子,转换代码如下:

// 省略上面赋值代码,与上面一致
StudentDO studentDO = new StudentDO();

BeanUtils.copyProperties(studentDTO, studentDO);

从用法可以看到,Spring BeanUtils 与 A

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值