JAVA對象拷貝 — Interge自動轉Long?效率比拼

前言

今天開發中遇到一個小問題。
因爲前期溝通不到位。有同學把一個後臺接口(用於獲取ES中的商品數據)的id相關字段,都設置成了Interge。而我們公司ID的要求是Long。

這導致數據後期維護十分不方便。還容易出錯,舉個例子
因爲泛型擦除所以並不會報錯且iidMap真實返回類型是Map<Interge, ItemTO>。導致調用iidMap.containsKey時用Long型是永遠取不到的。
在這裏插入圖片描述
因爲是Dubbo服務已經暴露出去。。。不太好收口。後期會廢棄使用新的接口。臨時的方案,準備用代理層,進行對象的拷貝。

那麼我們問題就變成如下2個問題

1:如何選擇JAVA Bean的Copy方式
2:Interge要能自動轉化爲Long

先把備的拷貝思路羅列出來

 1. 手工編碼
 2. 動態代理
 3. Spring反射
 4. 序列化  

有了思路,那我開搞,順道學習和複習總結一下JAVA對象的拷貝。
其中序列化方式,在這裏其實是可行的。首先後臺的量級不大,操作也方便,也能進行Interge和Long的轉換。相對的序列化有明顯的性能瓶頸,在大量操作時性能下降的特別快。

抱着好奇,我們一併探究並驗證下手工編碼,動態代理,Spring反射具體性能如何?能否轉換Interge和Long?

有了相關的思路,網上也找了一下文章,自己動手實現一下
具體代碼基本結構參考三石雨的文章大家可以看看

先看運行結果

在這裏插入圖片描述
5中方式的效率如圖所示。
效率來說:
手寫 > 動態代理 > 反射

 1. ManualCopy: 手動編寫,效率最高,能類型轉換,代碼量多
 2. Cglib:動態代理,效率高,不能進行類型轉換
 3. Apache Bean Utils , 反射,比較耗時,能進行類型轉換
 4. Spring Bean Utils :反射中等耗時,不能進行類型住哪換
 5. Apache Property Utils : 反射 類型不同,直接報錯。

代碼結構

來看看代碼結構。

  • Bean 源數據和目標數據(其中id類型不同)
  • Process類(策略模式)
  • 各類CopyMethod
  • PerformanceTest 單測類
    在這裏插入圖片描述

依賴

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

Bean

SourceBean :id爲Integer

package com.lctest.demo.lctrain.JavaBeanCopyTest.TO;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.Map;

/**
 * SourceBean :id爲Integer
 *
 * @author xiwen.chen
 * @since 2020-05-06
 */
@Setter
@Getter
public class SourceBean {

    private Integer iid;

    @JsonProperty("gmt_create")
    private Integer gmtCreate;

    private String name;

    @JsonProperty("actor_map")
    private Map<String, String> actorMap;
}

DestBean:對應Source的id 變爲 Long型

package com.lctest.demo.lctrain.JavaBeanCopyTest.TO;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.Map;

/**
 * DestBean:對應Source的id  變爲 Long型
 *
 * @author xiwen.chen
 * @since 2020-05-06
 */
@Setter
@Getter
public class DestBean {

    private Long iid;

    @JsonProperty("gmt_create")
    private Long gmtCreate;

    private String name;

    @JsonProperty("actor_map")
    private Map<String, String> actorMap;
}

Process類(策略模式)

package com.lctest.demo.lctrain.JavaBeanCopyTest;

import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.DestBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;

/**
 * desc
 *
 * @author xiwen.chen
 * @since 2020-05-06
 */
public class CopyProcessor {

    private int count;

    public CopyProcessor(int count) {
        this.count = count;
        System.out.println("性能測試=======" + this.count + "===========");
    }

    public void process(CopyMethod methodCallBack, SourceBean sourceBean) throws Exception {
        long processBegin = System.currentTimeMillis();
        DestBean destBean = null;
        System.out.println(methodCallBack.getMethodName() + "測試開始!");

        for (int i = 0; i < count; i++) {
            destBean = methodCallBack.beanCopy(sourceBean);
        }

        long processEnd = System.currentTimeMillis();
        long timeConsuming = processEnd - processBegin;
        System.out.println(methodCallBack.getMethodName() + "測試結束!共耗時" + timeConsuming + "毫秒,copy結果如下:");

        System.out.println(destBean.getName());
        System.out.println(destBean.getIid());
        System.out.println(destBean.getActorMap());
        System.out.println(destBean.getGmtCreate());
        System.out.println("=============================================");
    }
}

單測類

package com.lctest.demo.lctrain.JavaBeanCopyTest;

import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ApacheBeanUtilsCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ApachePropertyUtilsCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.CglibCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.ManualCopy;
import com.lctest.demo.lctrain.JavaBeanCopyTest.copymethod.SpringBeanUtilsCopy;
import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

/**
 * desc
 *
 * @author xiwen.chen
 * @since 2020-05-06
 */
public class PerformanceTest {

    private SourceBean sourceBean = null;

    private ManualCopy manualCopy = null;

    private CglibCopy cglibCopy = null;

    private ApacheBeanUtilsCopy apacheBeanUtilsCopy = null;

    private ApachePropertyUtilsCopy apachePropertyUtilsCopy = null;

    private SpringBeanUtilsCopy springBeanUtilsCopy = null;

    @Before
    public void init() {
        sourceBean = new SourceBean();
        sourceBean.setIid(445939013);
        sourceBean.setGmtCreate(1588694400);
        sourceBean.setName("xiwen copy bean test");
        Map<String, String> actorName = new HashMap<>();
        actorName.put("name1", "惜文");
        actorName.put("name2", "榮榮");
        actorName.put("name3", "新新");
        sourceBean.setActorMap(actorName);

        manualCopy = new ManualCopy();
        cglibCopy = new CglibCopy();
        apacheBeanUtilsCopy = new ApacheBeanUtilsCopy();
        apachePropertyUtilsCopy = new ApachePropertyUtilsCopy();
        springBeanUtilsCopy = new SpringBeanUtilsCopy();
    }

    @Test
    public void performTest10000() throws Exception {
        CopyProcessor copyProcessor = new CopyProcessor(10000);

        copyProcessor.process(apacheBeanUtilsCopy, sourceBean);
        copyProcessor.process(manualCopy, sourceBean);
        copyProcessor.process(cglibCopy, sourceBean);
        copyProcessor.process(springBeanUtilsCopy, sourceBean);
        copyProcessor.process(apachePropertyUtilsCopy, sourceBean);
    }
}

CopyMethod 5個具體實現類

接口


package com.lctest.demo.lctrain.JavaBeanCopyTest;

import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.DestBean;
import com.lctest.demo.lctrain.JavaBeanCopyTest.TO.SourceBean;

/**
 * desc
 *
 * @author xiwen.chen
 * @since 2020-05-06
 */
public interface CopyMethod {

    public String getMethodName();

    public DestBean beanCopy(SourceBean sourceBean) throws Exception;
}

實現類

public class ManualCopy implements CopyMethod {

    @Override
    public String getMethodName() {
        return "manual copy";
    }

    @Override
    public DestBean beanCopy(SourceBean sourceBean) throws Exception {
        DestBean destBean = new DestBean();

        destBean.setActorMap(sourceBean.getActorMap());
        destBean.setGmtCreate(sourceBean.getGmtCreate().longValue());
        destBean.setIid(sourceBean.getIid().longValue());
        destBean.setName(sourceBean.getName());

        return destBean;
    }
}

public class SpringBeanUtilsCopy implements CopyMethod {

    @Override
    public String getMethodName() {
        return "Spring Bean Utils";
    }

    @Override
    public DestBean beanCopy(SourceBean sourceBean) throws Exception {
        DestBean destBean = new DestBean();
        BeanUtils.copyProperties(sourceBean, destBean);

        return destBean;
    }
}

public class CglibCopy implements CopyMethod {

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

    @Override
    public String getMethodName() {
        return "Cglib BeanCopier";
    }

    @Override
    public DestBean beanCopy(SourceBean sourceBean) throws Exception {
        DestBean destBean = new DestBean();
        beanCopier.copy(sourceBean, destBean, null);
        return destBean;
    }
}

public class ApachePropertyUtilsCopy implements CopyMethod {

    @Override
    public String getMethodName() {
        return "Apache Property Utils";
    }

    @Override
    public DestBean beanCopy(SourceBean sourceBean) throws Exception {
        DestBean destBean = new DestBean();

        PropertyUtils.copyProperties(destBean, sourceBean);
        return destBean;
    }
}

public class ApacheBeanUtilsCopy implements CopyMethod {

    @Override
    public String getMethodName() {
        return "Apache Bean Utils";
    }

    @Override
    public DestBean beanCopy(SourceBean sourceBean) throws Exception {
        DestBean destBean = new DestBean();
        BeanUtils.copyProperties(destBean, sourceBean);
        return destBean;
    }
}

好了,得到結論,那我要開始手寫了轉換了。。。(:з」∠)~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章