幾種copyProperties工具類性能比較

一、事出有因

前段時間阿里發(fā)布了阿里巴巴代碼規(guī)約插件,果斷將它集成起來。右鍵->阿里編碼規(guī)約掃描,立即將不符合阿里編程規(guī)范的代碼現(xiàn)了原形,不得不服阿里想統(tǒng)一整個java市場的決心啊。怎么?竟然看到我最喜歡使用的Apache BeanUtils.copyProperties()方法后面打了個大大的紅叉,提示"避免使用Apache的BeanUtils進(jìn)行屬性的copy"。心里確實(shí)不是滋味,從小老師就教導(dǎo)我們,"凡是Apache寫的框架都是好框架",怎么可能會存在"性能問題"--還是這種猿們所不能容忍的問題。心存著對BeanUtils的懷疑開始了今天的研究之路。

二、市面上的其他幾種屬性copy工具
  1. springframework的BeanUtils
  2. cglib的BeanCopier
  3. Apache BeanUtils包的PropertyUtils類
三、下面來測試一下性能。
private static void testCglibBeanCopier(OriginObject origin, int len) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        System.out.println();
        System.out.println("================cglib BeanCopier執(zhí)行" + len + "次================");
        DestinationObject destination3 = new DestinationObject();

        for (int i = 0; i < len; i++) {
            BeanCopier copier = BeanCopier.create(OriginObject.class, DestinationObject.class, false);
            copier.copy(origin, destination3, null);
        }
        stopwatch.stop();

        System.out.println("testCglibBeanCopier 耗時: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    private static void testApacheBeanUtils(OriginObject origin, int len)
            throws IllegalAccessException, InvocationTargetException {
        Stopwatch stopwatch = Stopwatch.createStarted();
        System.out.println();
        System.out.println("================apache BeanUtils執(zhí)行" + len + "次================");
        DestinationObject destination2 = new DestinationObject();
        for (int i = 0; i < len; i++) {
            BeanUtils.copyProperties(destination2, origin);
        }

        stopwatch.stop();

        System.out.println("testApacheBeanUtils 耗時: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    private static void testSpringFramework(OriginObject origin, int len) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        System.out.println("================springframework執(zhí)行" + len + "次================");
        DestinationObject destination = new DestinationObject();

        for (int i = 0; i < len; i++) {
            org.springframework.beans.BeanUtils.copyProperties(origin, destination);
        }

        stopwatch.stop();

        System.out.println("testSpringFramework 耗時: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    private static void testApacheBeanUtilsPropertyUtils(OriginObject origin, int len)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Stopwatch stopwatch = Stopwatch.createStarted();
        System.out.println();
        System.out.println("================apache BeanUtils PropertyUtils執(zhí)行" + len + "次================");
        DestinationObject destination2 = new DestinationObject();
        for (int i = 0; i < len; i++) {
            PropertyUtils.copyProperties(destination2, origin);
        }

        stopwatch.stop();

        System.out.println("testApacheBeanUtilsPropertyUtils 耗時: " + stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

分別執(zhí)行1000、10000、100000、1000000次耗時數(shù)(毫秒):

工具名稱 執(zhí)行1000次耗時 10000次 100000次 1000000次
Apache BeanUtils 390ms 854ms 1763ms 8408ms
Apache PropertyUtils 26ms 221ms 352ms 2663ms
spring BeanUtils 39ms 315ms 373ms 949ms
Cglib BeanCopier 64ms 144ms 171ms 309ms
結(jié)論:
  1. Apache BeanUtils的性能最差,不建議使用。
  2. Apache PropertyUtils100000次以內(nèi)性能還能接受,到百萬級別性能就比較差了,可酌情考慮。
  3. spring BeanUtils和BeanCopier性能較好,如果對性能有特別要求,可使用BeanCopier,不然spring BeanUtils也是可取的。
四、Apache BeanUtils.copyProperties()性能分析

執(zhí)行1000000次copy屬性,然后通過jvisualvm查看方法耗時,如圖:


最耗時方法.png

發(fā)現(xiàn)最耗時的方法就是method.invoke(),但是spring的BeanUtils、PropertyUtils里也是采用反射來實(shí)現(xiàn)的,為什么效率相差這么大呢?

Paste_Image.png

看來Abstract.convert()和getIntrospectionData()占用了很大一部分時間.而且Apache BeanUtils中的日志輸出也比較耗時。

五、看看Spring BeanUtils和PropertyUtils
Apache BeanUtils和PropertyUtils對比.png

PropertyUtils和Apache BeanUtils核心代碼區(qū)別在圖中標(biāo)注的地方。Apache BeanUtils主要集中了各種豐富的功能(日志、轉(zhuǎn)換、解析等等),導(dǎo)致性能變差。

而Spring BeanUtils則是直接通過反射來讀取和寫入,直抒胸臆,省去了其他繁雜的步驟,性能自然不差。

Paste_Image.png
六、Cglib BeanCopier

cglib BeanCopier的主要耗時方法就在BeanCopier.create(),如果將該方法做成靜態(tài)成員變量,則還可以大大縮小執(zhí)行時間。BeanCopier是一種基于字節(jié)碼的方式,其實(shí)就是通過字節(jié)碼方式轉(zhuǎn)換成性能最好的get、set方式,只需考慮創(chuàng)建BeanCopier的開銷,如果我們將BeanCopier做成靜態(tài)的,基本只需考慮get、set的開銷,所以性能接近于get、set。BeanCopier源碼分析可見:http://m.itdecent.cn/p/f8b892e08d26,我這里就不展開了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,697評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,290評論 6 342
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,886評論 11 349
  • 就這么頹廢下去吧 就這樣吧 只要墮入深海 就不需要救贖
    露義蓮華君閱讀 337評論 0 0

友情鏈接更多精彩內(nèi)容