[性能] Bean拷贝工具类性能比较

Bean拷贝工具类性能比较

引言

几年前做过一个项目,接入新的api接口。为了和api实现解耦,决定将api返回的实体类在本地也建一个。这样做有两个好处

  1. 可以在api变更字段的时候保持应用稳定性
  2. 可以对返回的实体的属性做处理,以提高可读性。例如接口返回long类型的时间戳,则将该字段在本地实体类中对应字段设置为date类型方便使用。

大致是这样的一个应用场景。当时刚毕业,充斥的都是A.setName(B.getName)这种类型的代码。当字段非常多的时候看起来非常臃肿,最重要的给人感觉不优雅。

再给我一次机会

如果上天再给我一次机会,我会跟他说,我有四种工具类可以优雅的解决这个问题。
分别是

  • org.apache.commons.beanutils.PropertyUtils.copyProperties
  • org.apache.commons.beanutils.BeanUtils.copyProperties
  • org.springframework.beans.BeanUtils.copyProperties
  • net.sf.cglib.beans.BeanCopier

Talk is cheap, show me code

定义SourceBean

package com.zhaoyangwoo.model;

/**
 * Created by john on 16/7/28.
 */
 
public class SourceBean {

    private Integer age;

    private String title;
    
    private String source;

    private Boolean eat;
    
    public SourceBean(Integer i, String name, Boolean eat, String source) {
        this.age = i;
        this.title = name;
        this.eat = eat;
        this.source = source;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Boolean getEat() {
        return eat;
    }

    public void setEat(Boolean eat) {
        this.eat = eat;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public Integer getAge() {
        return age;
    }

}

定义DesBean

package com.zhaoyangwoo.model;

/**
 * Created by john on 16/7/28.
 */
 
public class DstBean {

    private Integer age;

    private String title;

    private Boolean eat;

    private String self;

    public String getSelf() {
        return self;
    }

    public void setSelf(String self) {
        this.self = self;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Boolean getEat() {
        return eat;
    }

    public void setEat(Boolean eat) {
        this.eat = eat;
    }
}

测试函数

package com.zhaoyangwoo.biz;

import com.zhaoyangwoo.model.DstBean;
import com.zhaoyangwoo.model.SourceBean;
import net.sf.cglib.beans.BeanCopier;

/**
 * Created by john on 16/7/28.
 */
public class BeanCopyMain {

private static BeanCopier beanCopier = BeanCopier.create(SourceBean.class, DstBean.class, false);


	public static void main(String[] args) throws Exception {

        Integer[] times = {10000, 1000, 10};

        for (int i = 0; i < times.length; i++) {

            Integer time = times[i];
            doCopy(time, (x, y) -> org.apache.commons.beanutils.PropertyUtils.copyProperties(y, x), "org.apache.commons.beanutils.PropertyUtils.copyProperties");
            doCopy(time, (x, y) -> org.apache.commons.beanutils.BeanUtils.copyProperties(y, x), "org.apache.commons.beanutils.BeanUtils.copyProperties");
            doCopy(time, (x, y) -> org.springframework.beans.BeanUtils.copyProperties(y, x), "org.springframework.beans.BeanUtils.copyProperties");
            doCopy(time, (x, y) -> beanCopier.copy(x, y, null), "net.sf.cglib.beans.BeanCopier.copy");
            doCopy(time, (x, y) -> {
                y.setEat(x.getEat());
                y.setTitle(x.getTitle());
                y.setAge(x.getAge());
            }, "getter/setter");
        }
    }

    static void doCopy(Integer time, BeanCopy beanCopy, String type) throws Exception {
        long startTime = System.currentTimeMillis();
        for (int j = 0; j < time; j++) {
            SourceBean sourceBean = new SourceBean(j, "source" + j, false, "abc");
            DstBean dstBean = new DstBean();
            beanCopy.copy(sourceBean, dstBean);
        }
        System.out.printf("执行%d次用时%dms---------%s%n", time, System.currentTimeMillis() - startTime, type);
    }

    interface BeanCopy {
        void copy(SourceBean from, DstBean to) throws Exception;
    }
}

执行结果如下

结论

根据上面的运行结果,我们可以得出以下结论

  • property少,写起来也不麻烦,就直接用传统的getter/setter,性能最好
  • property多,转换不频繁,那就省点事吧,使用org.apache.commons.beanutils.BeanUtils.copyProperties
  • property多,转换很频繁,为性能考虑,使用net.sf.cglib.beans.BeanCopier.BeanCopier,性能近乎getter/setter。但是BeanCopier的创建时消耗较大,所以不要频繁创建该实体,最好的处理方式是静态化或者缓存起来。
posted @ 2016-07-31 14:37  jiudianban  阅读(5665)  评论(0编辑  收藏  举报