Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils、Spring BeanUtils、Cglib BeanCopier)

文章转载自:Bean复制的几种框架性能比较

Bean复制的几种框架性能比较:

测试结果:

10次测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 54 57 50 53.66667 5.366666667
PropertyUtils.copyProperties 4 4 4 4 0.4
org.springframework.beans.BeanUtils.copyProperties 12 10 11 11 1.1
BeanCopier.create 0 0 0 0 0

10000次测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 241 222 226 229.6667 0.022966667
PropertyUtils.copyProperties 92 90 92 91.33333 0.009133333
org.springframework.beans.BeanUtils.copyProperties 29 30 32 30.33333 0.003033333
BeanCopier.create 1 1 1 1 0.1

10000次反转测验 第一次 第二次 第三次 平均值 每次平均值
BeanUtil.copyProperties 178 174 178 176.6667 0.017666667
PropertyUtils.copyProperties 91 87 89 89 0.0089
org.springframework.beans.BeanUtils.copyProperties 21 21 21 21 0.0021
BeanCopier.create 0 1 1 0.666667 6.66667E-05

注意:Cglib在测试的时候,先进行了实例的缓存,这个也是他性能较好的原因之一。如果把缓存去掉的话,性能就会出现了一些的差异,但是整体的性能还是很好,不过奇怪的是10000次反而比10次少,而且后面的反转1万次反而耗时最少,进行多次测试效果也是如此。
从整体的表现来看:

  • Cglib的BeanCopier的性能是最好的无论是数量较大的1万次的测试,还是数量较少10次,几乎都是趋近与零损耗。
  • Spring是在次数增多的情况下,性能较好,在数据较少的时候,性能比PropertyUtils的性能差一些。
  • PropertyUtils的性能相对稳定,表现是呈现线性增长的趋势。
  • 而Apache的BeanUtil的性能最差,无论是单次Copy还是大数量的多次Copy性能都不是很好
测验次数 10次 10000次 10000次反转
BeanCopier.create 41 28 10

cglib BeanCopier 使用小探究:

  • cglib是一款比较底层的操作java字节码的框架,其特性包括:
  1. 属性名称、类型都相同:拷贝OK
  2. 属性名称相同、类型不同:名称相同而类型不同的属性不会被拷贝
    注意:即使源类型是原始类型(int, short和char等),目标类型是其包装类型(Integer, Short和Character等),或反之:都不会被拷贝
  3. 源类和目标类有相同的属性(两者的getter都存在),但目标类的setter不存在 : 创建BeanCopier的时候抛异常。
    BeanCopoer类
    网上很多文章说是这里抛得异常:
    在这里插入图片描述
    我信你个鬼,糟老头子
    Debug追踪看一下代码执行过程,根本就没有执行generateClass方法中的代码呢(如果写错了,欢迎大家来吐槽,一起分析),也没有抛空指针异常,难道版本不一样吗!
    在这里插入图片描述
    在这里插入图片描述
  4. 源类或目标类的setter比getter少 : 拷贝OK。此时的setter多余,但不会报错。

当源和目标类的属性类型不同时,不能拷贝该属性,此时我们可以通过实现Converter接口来自定义转换器:
直接上代码吧:

package com.pica.cloud.patient.resident.server;

/**
 * @ClassName TargetClazz
 * @Description 目标类
 * @Author Chongwen.jiang
 * @Date 2019/7/25 17:18
 * @ModifyDate 2019/7/25 17:18
 * @Version 1.0
 */
public class TargetClazz {
    private Integer id;
    private String name;
    private String createTime;

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }


    public void setId(Integer id) {
        this.id = id;
    }
}

package com.pica.cloud.patient.resident.server;

import java.sql.Timestamp;

/**
 * @ClassName SourceClazz
 * @Description 源类
 * @Author Chongwen.jiang
 * @Date 2019/7/25 17:17
 * @ModifyDate 2019/7/25 17:17
 * @Version 1.0
 */
public class SourceClazz {
    private Integer id;
    private String name;
    private Timestamp createTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Timestamp getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Timestamp createTime) {
        this.createTime = createTime;
    }
}

package com.pica.cloud.patient.resident.server;

import org.springframework.cglib.core.Converter;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;

/**
 * @ClassName AccountConverter
 * @Description Bean属性类型转换器
 * @Author Chongwen.jiang
 * @Date 2019/7/25 17:56
 * @ModifyDate 2019/7/25 17:56
 * @Version 1.0
 */
public class TypeConverter implements Converter {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Object convert(Object value, Class target, Object o1) {
        if (value instanceof Integer) {
            return (Integer) value;
        } else if (value instanceof Timestamp) {
            Timestamp date = (Timestamp) value;
            return sdf.format(date);
        } else if (value instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal) value;
            return bd.toPlainString();
        }
        return null;
    }
}

package com.pica.cloud.patient.resident.server;

import com.alibaba.fastjson.JSON;
import com.pica.cloud.patient.resident.server.mapper.WechatUserMapper;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.test.context.junit4.SpringRunner;

import java.sql.Timestamp;

/**
 * @ClassName DbTest
 * @Description 测试类
 * @Author Jun.li0101
 * @Date 2019/3/21 13:25
 * @ModifyDate 2019/3/21 13:25
 * @Version 1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class DbTest {

    @Autowired
    private WechatUserMapper wechatUserMapper;

    @Test
    public void test1() {
        SourceClazz sourceClazz = new SourceClazz();
        sourceClazz.setId(12);
        sourceClazz.setName("loname");
        sourceClazz.setCreateTime(Timestamp.valueOf("2019-07-25 15:54:23"));

        final BeanCopier a = BeanCopier.create(SourceClazz.class, TargetClazz.class, true);

        TargetClazz targetClazz = new TargetClazz();
        TypeConverter typeConvert = new TypeConverter();
        a.copy(sourceClazz, targetClazz, typeConvert);
        System.out.println(JSON.toJSONString(targetClazz));

        Assert.assertEquals("2019-07-25 15:54:23", targetClazz.getCreateTime());



    }
}

注:一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。

发布了36 篇原创文章 · 获赞 4 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/weixin_41205148/article/details/97272157