【Java对象拷贝机制】「实战开发专题」高性能使用CGlib实现Bean拷贝(BeanCopier)指南

news2024/11/17 2:35:20

对象拷贝现状

业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度,代码因此变得臃肿不堪,使用一些方便的对象拷贝工具类将是很好的选择。

模型数据转换

项目中或多或少会对某些实体进行转换(DTO、VO、DO或者PO等),往往具有相同的属性名称,数量少的情况下我们可以直接采取set、get方法进行赋值,可是如果这样的转换在很多地方都会用到,还是靠set来进行操作势必会大大的影响开发效率。

  • 关于实体转换,我们把一个实体对应一张表(这可以当成DO)。

  • 业务中与第三方进行数据交互,我们需要把实体的数据传给他们,但不一定是一个DO中的所有属性可能减少或者多个DO中的属性组成,这里我们引入DTO(这个实体中我们可以去除一些隐私信息,比如:银行卡号,身份证,密码)。

  • 一个性别我们用1、2表示男女,页面中不能直接显示1或者2,需要显示男、女或者靓仔(男)、靓妹(女),这时候代表这样的一个实体我们可以看作VO。

目前流行的较为公用认可的工具类:

Apache的两个版本:(反射机制)

  • org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)

原因:dateTimeConveter的conveter没有对null值的处理


// targetObject特殊属性的限制:(Date,BigDecimal等)

public class BeanObject { //此处省略getter,setter方法
    private String name;
    private java.util.Date date;
}
 public class BeanObjectTest {  
    public static void main(String args[]) throws Throwable  {  
    BeanObject from = new BeanObject(); 
    BeanObject to = new BeanObject();  
    //from.setDate(new java.util.Date());
    from.setName("TTTT");
    org.apache.commons.beanutils.BeanUtils.copyProperties(to, from);//如果from.setDate去掉,此处出现conveter异常
    System.out.println(ToStringBuilder.reflectionToString(from));
    System.out.println(ToStringBuilder.reflectionToString(to));
    }  
}
  • org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object orig)

  • 相同属性名,且类型不匹配时候的处理

  • 原因:这两个工具类不支持同名异类型的匹配 !!!【包装类Long和原始数据类型long是可以的】

public class SourceClass {  //此处省略getter,setter方法
    private Long num;  
    private String name;
}

public class TargetClass {  //此处省略getter,setter方法
    private Long num;
    private String name;
}

public class PropertyUtilsTest {
    public static void main(String args[]) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException  {
        SourceClass from = new SourceClass();
        from.setNum(1);
        from.setName("name");
        TargetClass to = new TargetClass();
        //抛出参数不匹配异常
        org.apache.commons.beanutils.PropertyUtils.copyProperties(to, from);
        org.springframework.beans.BeanUtils.copyProperties(from, to);
        //抛出参数不匹配异常
        System.out.println(ToStringBuilder.reflectionToString(from));
        System.out.println(ToStringBuilder.reflectionToString(to));
    }
}

Spring版本:(反射机制)

  • org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)

cglib版本:(使用动态代理,效率高)

cglib是一款比较底层的操作java字节码的框架

  • net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)

工具操作

原理简介

反射类型:(apache)

都使用静态类调用,最终转化虚拟机中两个单例的工具对象。

public BeanUtilsBean(){
  this(new ConvertUtilsBean(), new PropertyUtilsBean());
}
  • ConvertUtilsBean可以通过ConvertUtils全局自定义注册。

    • ConvertUtils.register(new DateConvert(), java.util.Date.class);

    • PropertyUtilsBean的copyProperties方法实现了拷贝的算法。

  1. 动态bean:orig instanceof DynaBean:Object value = ((DynaBean)orig).get(name); 然后把value复制到动态bean类。

  2. Map类型:orig instanceof Map:key值逐个拷贝

  3. 其他普通类:从beanInfo【每一个对象都有一个缓存的bean信息,包含属性字段等】取出name,然后把sourceClass和targetClass逐个拷贝。

Cglib类型:BeanCopier

copier = BeanCopier.create(source.getClass(), target.getClass(), false);
copier.copy(source, target, null);

Get和set方法不匹配的处理

public class BeanCopierTest {
    /**
     * 从该用例看出BeanCopier.create的target.class 的每一个get方法必须有队形的set方法
     * @param args
     */
    public static void main(String args[]) {  
        BeanCopier copier = BeanCopier.create(UnSatifisedBeanCopierObject.class, SourceClass.class,false);
        copier = BeanCopier.create(SourceClass.class, UnSatifisedBeanCopierObject.class, false); //此处抛出异常创建 
    }  
}
class UnSatifisedBeanCopierObject {   
    private String name;
    private Long num;
    public String getName() {undefined
       return name;
    }
    public void setName(String name) {undefined
       this.name = name;
    }
    public Long getNum() {undefined
       return num;
    }
//  public void setNum(Long num) {undefined
//     this.num = num;
//  }
}

Create对象过程:产生sourceClass-> TargetClass 的拷贝代理类,放入jvm中,所以创建的代理类的时候比较耗时。最好保证这个对象的单例模式,可以参照最后一部分的优化方案。

创建过程 -> 源代码见jdk:

net.sf.cglib.beans.BeanCopier.Generator.generateClass(ClassVisitor)

  1. 获取sourceClass的所有public get 方法-》PropertyDescriptor[] getters

  2. 获取TargetClass 的所有 public set 方法-》PropertyDescriptor[] setters

  3. 遍历setters的每一个属性,执行4和5

  4. 按setters的name生成sourceClass的所有setter方法-》PropertyDescriptor getter【不符合javabean规范的类将会可能出现空指针异常】

  5. PropertyDescriptor[] setters-》PropertyDescriptor setter

  6. 将setter和getter名字和类型 配对,生成代理类的拷贝方法。

原理总结

Copy属性过程:调用生成的代理类,代理类的代码和手工操作的代码很类似,效率非常高。

上述这几种方式速度最快的是BeanCopier,默认只复制名称和类型相同的字段,还会对date为空的情况不进行复制。

我认为这样做最好,比如对象A的值复制到B中,我们把相同的进行复制,把不同的,也就是需要我们个性化的一些字段,单独出来用get来赋值,这样程序就会很明确,重点也就聚焦在了不同的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107788.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

训练seq2seq模型的一些Tips——李宏毅机器学习笔记

Copy Mechanism 有时我们并不需要decoder创造一些东西出来,有些内容是可以从encoder复制而来。 最早具有复制能力的模型:Pointer Network 例如: chat-bot Summarization 至少要训练百万篇文章 Guided Attention Monotonic Attention Lo…

PPT怎么转化成PDF?这两种方法教你快速解决!

今天我们将向您介绍如何将 PowerPoint 演示文稿 (PPT) 转换为 PDF 文件。 我们将通过两种方法来做到这一点: 将 PowerPoint 演示文稿另存为 PDF 文件。使用 奇客免费PDF转换 将 PowerPoint 演示文稿转换为 PDF。方法一:使用 Microsoft PowerPoint 将 P…

合理利用chatGpt之新冠阳性

🏆今日学习目标: 🍀合理利用chatGpt之新冠阳性 ✅创作者:林在闪闪发光 ⏰预计时间:30分钟 🎉个人主页:林在闪闪发光的个人主页 🍁林在闪闪发光的个人社区,欢迎你的加入:…

AI 预测到了正确的世界杯胜利者吗 ?

在过去的一个月里,卡塔尔 2022 年世界杯让我们目睹了一个又一个令人震惊的结果,甚至在决赛之前,让所有人的目光都聚焦在法国和阿根廷两支球队上,其实在球迷们心中,早就开始了各种猜测。😄现在是时候回顾一下…

基于CNN和LSTM的气象图降水预测示例

我们是否可以通过气象图来预测降水量呢?今天我们来使用CNN和LSTM进行一个有趣的实验。 我们这里使用荷兰皇家气象研究所(也称为KNMI)提供的开放数据集和公共api,来获取数据集并且构建模型预测当地的降水量。 数据收集 KNMI提供的数据集,我…

excel函数公式大全,最常用的6个公式

Excel中的函数引用一些预定义的公式,可以通过输入参数值来计算函数的对应函数,并且函数名称基本上与函数相对应,这很容易记住。在日常工作中,功能可用于数据统计、计算、处理和分析。本文主要介绍EXCEL中一些常用公式,…

视唱练耳训练小程序开发,摆脱传统训练制约性

视唱练耳作为一门综合性的音乐基础理论学科,对于声乐、器乐、舞蹈等音乐学科中的各个方面都起着十分重要的作用,尤其是突出表现在基本理论、基本技能和音乐审美上,对培养和发展学生的乐感、唱奏技巧以及音乐思维等都有着非常重要的意义。世界…

Databend 开源周报 #71

Databend 是一款强大的云数仓。专为弹性和高效设计,自由且开源。 即刻体验云服务:https://app.databend.com。 What’s New 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 Features & Improvements Planner 优化集群模…

简单易用的监控告警系统 | HertzBeat 在 Rainbond 上的使用分享

在现有的监控告警体系中 Prometheus AlertManger Grafana 一直是主流,但对于中小团队或个人来说,这种体系显的较为复杂。而 HertzBeat 能让中小团队或个人很快速的搭建监控告警系统,并通过简单的配置实现应用、数据库、操作系统的监控与告警…

k8s HPA升级 KEDA 基于事件驱动的自动伸缩

说明:KEDA有啥用,相对HPA有啥优势。HPA针对于cpu,内存来进行弹性伸缩,有点不太精确。KEDA可以接入prometheus,根据prometheus的数据指标进行弹性伸缩,相比更加的精准实用。 安装k8s环境部署prometheus 创建ns&#xf…

HashMap最全面试题

文章目录一、 存储结构字段结构二、索引计算三、put方法四、扩容机制五、其他一、 存储结构 HashMap的底层数据结构是什么? 在JDK1.7 和JDK1.8 中有所差别: 在JDK1.7 中,由“数组链表”组成,数组是 HashMap 的主体,链…

Django学习Day6

1.ORM故障处理 1)当执行python manager.py makemigrations出现迁移问题时,如何进行解决。 处理方案:在models.py中,为book表的des非空字段设置一个默认值。 2)数据库的迁移文件混乱问题 数据库中的django_migrations记录了migra…

健康指标管理系统

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字): 模块划分:公告类型、公告信息、地区信息、用户信息、人员分类、人员信息、指标信息、健康信息 管理员功能&a…

Java+MYSQL基于ssm在线投票管理系统

随着社会的发展,人们在处理一些问题的时候不同意见越来越多,这源于人们对思想的解放和对社会的认识。所以在处理同一问题上,为了征求不同人的意见在线投票系统诞生了。 传统的投票模式都是通过人工手动填写问卷的方式来进行,这在很大程度上会造成人力和资源上的浪费。随着科技的…

擎创技术流 | ClickHouse实用工具—ckman教程(7)

​ ​一期一会的“ckman”教程又跟大家见面了,本期分享的重点主要针对上期后台陆续收到的问题展开,解答完问题后再带入一些关于“ckman”升级的相关讲解。感兴趣的朋友可以先关注一波。还是老规矩,先带大家复习下前几期的分享内容↓↓↓ 擎创…

springboot整合mongodb 保姆级教程

1、确保mongodb是否安装 Linux安装docker 保姆级教程_ 来杯咖啡的博客-CSDN博客&#xff08;可以看这篇文章&#xff09; 2、代码展示 2.1 使用 MongoTemplate 创建boot项目&#xff0c;导入架包。 <?xml version"1.0" encoding"UTF-8"?> <p…

带你深入了解一下vue.js中的this.$nextTick!

我们先看看nextTick究竟是个啥&#xff1f; console.log(this.$nextTick); // 控制台打印 if(fn){return nextTick(fn, this); } 我们可以看出nextTick就是一个方法&#xff0c;方法有两个参数&#xff1a;fn和this&#xff0c;fn就是需要传的回调函数&#xff0c;this就是所…

主轴承盖螺栓拧紧机PLC控制程序

HMI为西门子TP900触摸屏&#xff0c;支持屏幕触摸和按键操作 设备主要参数 设备外形尺寸&#xff1a;长*宽*高 2180*1900*2500mm 生产节拍&#xff1a; 55 S 电源电压&#xff1a; AC380V5%&#xff0c;50HZ&#xff0c;三相五线制 系统组态 常见故障处理 气缸报警 报警原…

Windows下安装VTK8.2.0

Windows下安装VTK8.2.0 1、依赖 VS2017 Qt5 cmake 2、前期准备 2.1、访问vtk官方下载VTK8.2.0源码 VTK源码下载地址&#xff1a;https://vtk.org/download/ 2.2、配置环境变量 配置CMAKE_PREFIX_PATH&#xff0c;值为Qt的bin路径 2.3、新建2个文件夹一个用于存放cm…

11 个有用的现代 JavaScript 技巧

在我们日常开发工作中&#xff0c;我们经常使用到字符串的转换、检查它是否存在的对象中的键、有条件地操作对象数据、过滤数组中的假值等。 在这里&#xff0c;我整理了一些很棒的JavaScript的技巧&#xff0c;这些技巧是我个人最喜欢的&#xff0c;因为它使我的代码更短更干…