[性能] 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的創建時消耗較大,所以不要頻繁創建該實體,最好的處理方式是靜態化或者緩存起來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM