BeanCopier几种框架的比较

项目中常遇到bean copy场景,本文对spring、oracle、Apache等开源的bean copy框架进行性能测试。介绍了几种框架及其内部实现原理,通过JMH进行多组测试,包括不同线程数和属性数量。结论表明,实例字段少用get/set,无converter用cglib,字段量大并发高用orika,不建议用Apache的框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目中的通常都会遇到bean copy的场景,spring,oracle,Apache都有自己的开源bean copy框架,大家常常会困扰到底哪个框架的性能最好,下面对各个框架的性能测试,帮助大家在开发中使用合适自己的bean copy框架:

 

目前项目中使用的的几种BeanCope的框架:

1.org.springframework.beans.BeanUtils,version 4.3.18-RELEASE

2.org.apache.commons.beanutils.PropertyUtils, version 1.9.3-RELEASE

3.org.apache.commons.beanutils.BeanUtil, version 1.9.3-RELEASE

4.cglib我用的是spring带的:org.springframework.cglib.beans.BeanCopier, version 4.3.18-RELEASE

5.ma.glasnost.orika.impl.DefaultMapperFactory, version 1.5.2-RELEASE

6.get/set

(直接想看结论的直接跳到最后)

内部实现原理:1,2,3前三个框架是都是通过反射原理实现,大致的方法就是通过反射获取字段名来匹配目标类的字段

4,5是通过字节码实现的,具体实现可以看相关源码

 

测试框架:JMH

# Warmup: 20 iterations, 1 s each

# Measurement: 20 iterations, 1 s each

# Timeout: 10 min per iteration

# Threads: 50 threads, will synchronize iterations

# Benchmark mode: Average time, time/op

预热20s,执行60s,线程50,模式为平均时间

 

测试类:

public class FromBean {
 
    private String string1;
 
    private String string2;
 
    private Integer integer1;
 
    private Long long1;
     
    private Date date1;
}
 
public class ToBean {
 
    private String string1;
 
    private String string2;
 
    private Integer integer1;
 
    private Long long1;
 
    private Date date1;
}

测试方法:

public void springbean(FromBean fromBean){
    ToBean toBean = new ToBean();
    try {
        BeanUtils.copyProperties(fromBean, toBean);
    } catch (Exception e){}
}
 
public void springbeanlom(FromBean fromBean){
    ToBeanLombok toBean = new ToBeanLombok();
    try {
        BeanUtils.copyProperties(fromBean, toBean);
    } catch (Exception e){}
}
public void apacheproperty(FromBean fromBean){
    ToBean toBean = new ToBean();
    try {
        PropertyUtils.copyProperties(toBean, fromBean);
    } catch (Exception e){}
}
 
public void cglib(FromBean fromBean){
    ToBean toBean = new ToBean();
 
    try {
        BeanCopier beanCopier = BeanCopier.create(FromBean.class, ToBean.class, false);
        beanCopier.copy(fromBean, toBean, null);
    } catch (Exception e){}
}
 
public void orika(FromBean fromBean){
    //MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); 每次创建消耗很大,先初始化该factory
    try {
        ToBean toBean = mapperFactory.getMapperFacade().map(fromBean, ToBean.class);
    } catch (Exception e){}
}
 
public void getset(FromBean fromBean){
    ToBean toBean = new ToBean();
    try {
        toBean.setString1(fromBean.getString1());
        toBean.setString2(fromBean.getString2());
        toBean.setInteger1(fromBean.getInteger1());
        toBean.setLong1(fromBean.getLong1());
        toBean.setDate1(fromBean.getDate1());
    } catch (Exception e){}
}

测试1:单线程,5项属性:string,string,integer,long,date

org.springframework.beans.BeanUtils
0.288
0.348
0.278
org.apache.commons.beanutils.PropertyUtils
3.257
4.826
2.891
org.apache.commons.beanutils.BeanUtils
5.467
6.121
5.366
org.springframework.cglib.beans.BeanCopier
0.079
0.097
0.076
ma.glasnost.orika.impl.DefaultMapperFactory
0.444
3819.167
0.453
7072.294
0.440
3208.739
get,set
0.027
0.045
0.024

orika初始化mapperFactory 消耗的时间很长,下面面是每次都初始化的时间。

测试2:单线程,6项属性:string,string,integer,long,date + innerBean

在bean中新增了一个属性为innerBean:先看一下copy方法是不是深拷贝。

public class InnerBean {
 
    private String stirng1;
 
    private Integer integer1;
 
    private Date localDate;
 
    public String getStirng1() {
        return stirng1;
    }
 
    public void setStirng1(String stirng1) {
        this.stirng1 = stirng1;
    }
 
    public Integer getInteger1() {
        return integer1;
    }
 
    public void setInteger1(Integer integer1) {
        this.integer1 = integer1;
    }
 
    public Date getLocalDate() {
        return localDate;
    }
 
    public void setLocalDate(Date localDate) {
        this.localDate = localDate;
    }
}

结果是只有orika的方法是深拷贝,其他都是直接引用的原来的innerBean。

org.springframework.beans.BeanUtils

0.317

org.apache.commons.beanutils.PropertyUtils

3.509

org.apache.commons.beanutils.BeanUtils5.996
org.springframework.cglib.beans.BeanCopier0.069
ma.glasnost.orika.impl.DefaultMapperFactory0.466
get,set0.001

测试3:20线程,6项属性:string,string,integer,long,date + innerBean

org.springframework.beans.BeanUtils

2.909

org.apache.commons.beanutils.PropertyUtils

38.671

org.apache.commons.beanutils.BeanUtils

63.438

org.springframework.cglib.beans.BeanCopier0.638
ma.glasnost.orika.impl.DefaultMapperFactory10.472
get,set0.005

测试4:50线程,6项属性:string,string,integer,long,date + innerBean

org.springframework.beans.BeanUtils

7.736

org.apache.commons.beanutils.PropertyUtils

12618.541

org.apache.commons.beanutils.BeanUtils

19641.511

org.springframework.cglib.beans.BeanCopier1.767
ma.glasnost.orika.impl.DefaultMapperFactory25.192
get,set0.013

测试5:20线程,21项属性:string5,integer5,long5,date5 + innerBean

org.springframework.beans.BeanUtils

10.389

org.apache.commons.beanutils.PropertyUtils

143.143

org.apache.commons.beanutils.BeanUtils

239.994

org.springframework.cglib.beans.BeanCopier0.825
ma.glasnost.orika.impl.DefaultMapperFactory10.574
get,set0.005

测试6:50线程,21项属性:string5,integer5,long5,date5 + innerBean

测试7:20线程,41项属性:string10,integer10,long10,date10 + innerBean

测试8:50线程,41项属性:string10,integer10,long10,date10 + innerBean 见总表

org.springframework.beans.BeanUtils

0.317

2.909

7.736

10.389

28.94922.98060.596
org.apache.commons.beanutils.PropertyUtils

3.509

38.671

12618.541

143.143

23123//
org.apache.commons.beanutils.BeanUtils5.996

63.438

19641.511

239.994

26611//
org.springframework.cglib.beans.BeanCopier0.0690.6381.7670.8254.6210.8964.159
ma.glasnost.orika.impl.DefaultMapperFactory0.46610.47225.19210.57428.68410.84929.388
get,set0.0010.0050.0130.0050.0130.0050.013

 

结论:

直接用get,set是最快的,如果实例字段比较少的情况下,建议直接使用get,set。

cglib在没有converter的情况下性能是最好的,如果有converter的话要具体看converter的实现,总体速度也是很快的,建议不需要或简单converter场景的使用。

Spring beanUtils 和orika在并发低情况下速度相当,当线程增加以及字段量增加的时候,orika性能逐渐有优势(orika对于21属性和41属性速度差不多,而spring beanUtils由于是基于反射实现,属性增加耗时也相应增加)。orika劣势在于需要初始化Factory,每个类转换都需要注册到factory,使用起来比较繁琐,orika优势在于字段量大,并发高的场景,并且orika是深拷贝可以自己定义转换字段,所以推荐在需要的情况使用。

Apache的相对比较慢,不建议使用。

推荐大家使用cglib和orika

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值