对象的拷贝在开发过程中肯定非常常见,想必大家使用spring中的BeanUtils.copyProperties来完成的,小编最初也是用习惯了这个工具,但是在一次codereview中,大佬给我提出建议使用cglib的BeanCopier.copy方法来进行处理,也和我解释了前者性能比较差。所以我后来也去看了一下相关的源码。

BeanUtils.copyProperties:

 private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties) throws BeansException {Assert.notNull(source, "Source must not be null");Assert.notNull(target, "Target must not be null");Class<?> actualEditable = target.getClass();if (editable != null) {if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;PropertyDescriptor[] var7 = targetPds;int var8 = targetPds.length;for(int var9 = 0; var9 < var8; ++var9) {PropertyDescriptor targetPd = var7[var9];Method writeMethod = targetPd.getWriteMethod();if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {Method readMethod = sourcePd.getReadMethod();if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}Object value = readMethod.invoke(source);if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}writeMethod.invoke(target, value);} catch (Throwable var15) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);}}}}}}

BeanCopier.copy:

        public BeanCopier create() {Object key = BeanCopier.KEY_FACTORY.newInstance(this.source.getName(), this.target.getName(), this.useConverter);return (BeanCopier)super.create(key);}public void generateClass(ClassVisitor v) {Type sourceType = Type.getType(this.source);Type targetType = Type.getType(this.target);ClassEmitter ce = new ClassEmitter(v);ce.begin_class(46, 1, this.getClassName(), BeanCopier.BEAN_COPIER, (Type[])null, "<generated>");EmitUtils.null_constructor(ce);CodeEmitter e = ce.begin_method(1, BeanCopier.COPY, (Type[])null);PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(this.source);PropertyDescriptor[] setters = ReflectUtils.getBeanGetters(this.target);Map names = new HashMap();for(int i = 0; i < getters.length; ++i) {names.put(getters[i].getName(), getters[i]);}Local targetLocal = e.make_local();Local sourceLocal = e.make_local();if (this.useConverter) {e.load_arg(1);e.checkcast(targetType);e.store_local(targetLocal);e.load_arg(0);e.checkcast(sourceType);e.store_local(sourceLocal);} else {e.load_arg(1);e.checkcast(targetType);e.load_arg(0);e.checkcast(sourceType);}for(int i = 0; i < setters.length; ++i) {PropertyDescriptor setter = setters[i];PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());if (getter != null) {MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());if (this.useConverter) {Type setterType = write.getSignature().getArgumentTypes()[0];e.load_local(targetLocal);e.load_arg(2);e.load_local(sourceLocal);e.invoke(read);e.box(read.getSignature().getReturnType());EmitUtils.load_class(e, setterType);e.push(write.getSignature().getName());e.invoke_interface(BeanCopier.CONVERTER, BeanCopier.CONVERT);e.unbox_or_zero(setterType);e.invoke(write);} else if (compatible(getter, setter)) {e.dup2();e.invoke(read);e.invoke(write);}}}e.return_value();e.end_method();ce.end_class();}

可以看到前者是使用反射进行copy的对象,后者通过字节码技术生成一个代理类,直接调用这个类的set,get方法进行赋值。

而反射之所以慢是因为我们字节码文件在编译过程中会用到 即时编译器(JIT 编译器,Just In Time Compiler,这个编译器再将我们代码交给jvm之前会进行优化一遍,而反射需要动态解析,编译器无法优化,就会直接调用jvm的方法,这样效率就比较低下。所以从性能考虑建议使用BeanCopier.copy,当然也有其他的工具类效率更高的,但是各有各的优缺点,怎么选择看实际业务场景需要啦

性能篇之对象拷贝工具BeanUtils.copyProperties和BeanCopier.copy的比较相关推荐

  1. 对象拷贝 Apache BeanUtils与Spring BeanUtils性能比较

    前言 在我们实际项目开发过程中,我们经常需要将不同的两个对象实例进行属性复制,从而基于源对象的属性信息进行后续操作,而不改变源对象的属性信息,比如DTO数据传输对象和数据对象DO,我们需要将DO对象进 ...

  2. 【Java生态圈技术总结】之深度剖析MapStruct对象拷贝工具

    目录导航 一.常用的对象拷贝工具基本介绍 1.1 Apache BeanUtils 1.2 Spring BeanUtils 1.3 cglib BeanCopier 1.4 HuTool BeanU ...

  3. spring boot 对象拷贝工具(Orika)

    1.spring 自带拷贝工具 LoginUser user = new LoginUser(); // 将data中字段相同的属性拷贝到user中BeanUtils.copyProperties(d ...

  4. Java基础篇:对象拷贝:clone方法 以及 序列化

    我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...

  5. 对象拷贝之Apache BeanUtils、Spring的BeanUtils、Mapstruct、BeanCopier、PropertieyUtils对比(深拷贝)

    大多时候时候使用的是Apache或Spring``BeanUtils,今天,我们来看一下一个更高效的属性拷贝方式:BeanCopier. https://github.com/cglib/cglib ...

  6. Bean的拷贝之BeanUtils

    本文来说下Bean的各类拷贝工具 文章目录 概述 对象拷贝 BeanUtils apache的BeanUtils spring的BeanUtils cglib BeanCopier Hutool Be ...

  7. 6种常用Bean拷贝工具一览

    在我们日常的工作中,经常需要做对象的拷贝或转化,例如在传递参数时,把入参的DTO转化为PO存入数据库,在返回前端时把PO再转化为VO.如果再分的细一点,可能还会有DO(Domain Object),T ...

  8. Java 对象深拷贝工具类

    目录 1. 使用场景 1.1 场景一 1.2 场景二 2. Spring 中的对象拷贝 3. 本工具类中的对象拷贝 3.1 拷贝对象本身(单个) 3.2 拷贝对象本身(批量) 3.3 拷贝对象属性至其 ...

  9. 使用org.springframework.beans.BeanUtils..copyProperties(sourse, target)方法复制属性

    使用org.springframework.beans.BeanUtils..copyProperties()方法进行copy两个类的属性. 注意: 1.源类Sourse中的属性需有get方法: 2. ...

最新文章

  1. MVC应用程序播放RealPlayer(rmvb)视频
  2. 防火墙(14)——实现路由转发功能(2)
  3. 磁盘的块大小(Block Size)和扇区大小(Sector Size)
  4. 第一个JDK 10(18.3)候选版本(内部版本43)展示了新的版本控制方案
  5. WeMos-D1R2的使用
  6. Glide 这样用,更省内存!!! 1
  7. bzoj 3367: [Usaco2004 Feb]The Big Game 球赛(DP)
  8. Java Thread.yield详解
  9. 网上提交材料时让登记照瞬间符合审核尺寸要求的小工具
  10. TikTok二面:“聊聊二维码扫码登录的原理”
  11. 【有利可图网】PS实战教程55:打破次元壁,将照片从三次元跨越到二次元
  12. java 熄灯问题_遍历搜索空间的例子:熄灯问题
  13. linux mkdir命令用法,常用Linux运维命令 - mkdir命令用法详解
  14. java基础题数组_java基础学习——数组笔试题
  15. shell脚本_ grep和egrep命令
  16. 3、Windows之CMD装逼命令————CMD命令打开网页(让人一看你就是个电脑高手)
  17. 07. 快速生成树协议
  18. ES6-Promise简介
  19. java学习四个月以来的想法
  20. java 压缩 tar_Java将文本文件压缩为tar.gz

热门文章

  1. 毕业论文找文献是个问题,我直接用python把全网文献爬了一遍,这波就很舒服
  2. 无需编程,基于甲骨文oracle数据库零代码生成CRUD增删改查RESTful API接口
  3. 一篇文章认识《双目立体视觉》
  4. Ubuntu使用时的小问题
  5. 浙大PatC语言练习50-76
  6. HC05蓝牙模块与手机APP连接
  7. r语言 网站数据查找
  8. 常用的十大Python开发工具
  9. 计算机服务器排名,2019服务器CPU天梯图 多路CPU性能排名
  10. 银河麒麟服务器版本搭建本地源2.0