Java Bean Copy组件的性能比较

公司系统中以前一直有使用组件进行Bean copy的操做,只是知道此操做对性能有影响,可是到底有多少影响内心一直没有数。如今对Bean copy进行测试获取量化的结果java

目前Bean Copy的主流组件:spring

  • Apache BeanUtils缓存

  • Spring BeanUtilsbash

  • Cglib BeanCopier多线程

    众所周知Apache BeanUtils性能太差,通常不推荐使用。这里不对其进行测试,只测试后面两个组件app

测试环境:

  • JAVA8
  • Spring Boot 2.1.4.RELEASE
  • 本地普通台式机

测试代码:

测试功能:循环N次,将TelAppModel 对象中的属性复制到TelAppDto中,统计每种组件花费的时间,花费时间越少的性能越强。oop

测试POJO类 源类 TelAppModel.java 和目标类 TelAppDto.java,两个类都是简单的pojo类且成员变量相同。性能

普通的Java set/get方法实现Bean Copy, 代码以下:测试

public static void copySetGet(TelAppModel source, TelAppDto target){
       target.setId(source.getId());
       target.setTelPowerSavingMode((byte)0);
       target.setTelSecret(source.getTelSecret());
       target.setTelAppId(source.getTelAppId());
       target.setTelName(source.getTelName());
       target.setDesc(source.getDesc());
   }
复制代码

Spring BeanUtils实现Bean Copy代码以下:优化

public static void copyPropertiesSpring(Object source, Object target){
    BeanUtils.copyProperties(source, target);
}
复制代码

Cglib BeanCopier实现Bean Copy代码以下:

public static void copyPropertiesCglib(Object source, Object target){
    BeanCopier beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
    beanCopier.copy(source, target, null);
}
复制代码

测试代码: longCount:定义复制执行的次数

// 在执行Bean copy前 先初始化 longCount 个TelAppModel,作为测试素材

for(int i = 0; i < longCount; i++){
      appModelSourceList.add(createModel());
}
复制代码

3种Bean copy方法依次调用此test()方法:

// set/get方法
test((a,b) -> copySetGet(a, b));

// spring BeanUtils
test((a,b) -> copyPropertiesSpring(a, b));

// spring BeanCopier
test((a,b) -> copyPropertiesCglib(a, b));
复制代码

// 此方法依次将列表中TelAppModel对象复制到TelAppDto对象中,并打印执行longCount次花费的时间,为了保证结果准确,以上操做执行3次,即3*longCount次

private void test(BiConsumer<TelAppModel, TelAppDto> biConsumer){
    int runNum = 3;
    for(int k = 0; k < runNum; k++) {
        long loopCount = longCount;
        long begin = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            TelAppModel telAppModel1 = appModelSourceList.get(i);
            TelAppDto telAppDto = new TelAppDto();
            biConsumer.accept(telAppModel1, telAppDto);
        }
        System.out.println((System.currentTimeMillis() - begin));
    }
}
复制代码

测试报告:

分别执行1000、10000、100000、1000000次耗时数(毫秒): 详细时间以下:

在这里插入图片描述
数据分析

  • ○ set/get方法理论上应该是最快的
  • ○ 性能以下: set/get方法 > Cglib BeanCopier > Sprign BeanUtils
  • ○ Spring BeanUtils每次第一次循环花费时间特别多,和后面二次不在一个数据量,数据有异常

在执行命令时,经过jvisualvm查看CPU的耗时时间,详细以下:

在这里插入图片描述
图表分析:

  • Spring BeanUtils第一次执行CachedIntrospectionResults.forClass()方法时,会将class信息从磁盘加载到内存缓存,而后后续的操做会从缓存中获取class信息。这也解释了为何Spring BeanUtils为何会比较慢的缘由。另外此操做是同步的,若是多线程同时加载相同的class,会出现阻塞的状况。
  • Spring BeanUtils的copyProperties占用的CPU也比较多,说明真正执行copy Bean操做依然会花费较多的时间
  • 观察上图,发现BeanCopier主要花费的时间是调用create()方法,真正执行copy Bean花费的时间较少,如今咱们根据此进行优化,执行Bean Copy时,不是每次执行建立新BeanCopier,而是使用将BeanCopier.create()建立的BeanCopier进行缓存,修改后代码以下:
static BeanCopier beanCopierStatic = BeanCopier.create(TelAppModel.class, TelAppDto.class, false);
 
 public static void copyPropertiesCglibStatic(Object source, Object target){
     beanCopierStatic.copy(source, target, null);
 }
复制代码

再分别执行1000、10000、100000、1000000次耗时数(毫秒): 详细时间以下:

在这里插入图片描述

分析: Cglib BeanCopier优化,性能大大提升。cglib在性能和set/get方法相差不大

结论:

spring beanUtils 和 cglib 性能都还能够接受,若是对性能没有很是苛刻的要求,使用cglib或spring bean utils 问题都问题不大,推荐优先使用cglib
复制代码
相关文章
相关标签/搜索