• Java对象属性复制备忘


    基于面向对象和各种设计要求,一个分层的Java系统中存在各种 VO、DTO、BO、PO 之类的对象,同一个实体的不同对象需要大量的属性复制,为了避免手动操作,需要一种便捷对象浅复制工具类,下面是各个常见工具对比。

    列举

    //cglib
    net.sf.cglib.beans.BeanCopier.create 
    net.sf.cglib.beans.BeanCopier.copy
    
    //spring-beans
    org.springframework.beans.BeanUtils.copyProperties
    
    //commons-beanutils
    org.apache.commons.beanutils.BeanUtils.copyProperties
    org.apache.commons.beanutils.PropertyUtils.copyProperties
    

    原理

    以上4种方式都是通过自动调用原对象的getter方法,再用目标对象的setter方法设置进去,区别在于BeanCopier先通过create创建了一个以BeanCopier派生的动态代理类,其创建的copy方法实现包含以上所有getter和setter的调用过程,调用copy可以达到原生代码方式的性能;而其他所有方式如spring-beans和commons-beanutils的实现都是通过反射逐个调用getter和setter,性能相比前者较差。

    细节

    细节 Apache-PropertyUtils Apache-BeanUtils Spring-BeanUtils Cglib-BeanCopier
    相同属性名,不同类型转换Converter扩展 NO Yes Yes Yes,较难用,需要对每一种属性类型都做转换
    相同属性名,Integer和int的处理 OK OK OK 不拷贝,忽略该属性
    相同属性名,Long和Integer的处理 异常报错 OK,自动互转 不拷贝,忽略该属性 不拷贝,忽略该属性
    对基本类型null值处理(Integer,Long等) OK 特殊,会将null转为0,用Converter后解决 OK OK
    对source特殊属性的限制:(Date,BigDecimal等) OK NO,异常出错,必须用Converter才行 OK OK
    Get和set方法不匹配的处理 OK,忽略该属性 OK,忽略该属性 OK,忽略该属性 创建异常(仅限source有get方法在target中找不到对应set方法)
    调用异常处理 需处理异常 需处理异常 RuntimeException RuntimeException

    需要兼容性的场景,优先spring-beans提供的BeanUtils,功能强大,兼容性最好。需要性能的场景,优先选择cglib提供的BeanCopier,性能最好(注意需要缓存create结果)。

    还有一项需要注意的是所有拷贝都是浅拷贝,注意属性引用不变,避免新老对象同时读写引起问题,这需要通过场景约束。

    结论

    事实上,由于不同工具类实现不同,细节差异非常多,一个团队最好通过规范统一使用某一个,并对其熟悉和理解,不必追求万能的工具类。我在新项目中选择了BeanCopier,并通过场景和限制约定避免踩坑。

    • 场景约束:主要用于同模型的DO、DTO和VO等之间转换。
    • 限制约定:要求两者同名属性具有严格相同类型,且其getter和setter一一对应,不能包含特殊逻辑。
  • 相关阅读:
    NTFS 的默认簇大小
    磁盘管理中显示的磁盘顺序(磁盘0、磁盘1、磁盘2)与接口(sata、pci、nvme)之间的关系
    FastCopy可以拷贝文件保留原创建日期+几种模式
    三款数据恢复软件
    windows的存储池和存储空间(windows10新建好存储空间后,系统会根据分区容量的大小自动设置簇大小,如需更改,请到磁盘管理中删除分区后新建简单卷)
    响应式web原型设计工具——froont
    单个硬盘和软raid 0(windows 存储空间的存储池)性能对比(结果是差不多:()
    怎样使用工具更改磁盘簇大小
    存储空间概述(微软文档)
    申请微信商户API证书、设置AIPv2密钥\设置AIPv3密钥
  • 原文地址:https://www.cnblogs.com/pyx0/p/copy-properties.html
Copyright © 2020-2023  润新知