<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么阿里巴巴禁止使用Apache Beanutils進(jìn)行屬性的copy?

          共 1105字,需瀏覽 3分鐘

           ·

          2020-07-30 17:44

          △Hollis, 一個對Coding有著獨(dú)特追求的人△
          這是Hollis的第?297?篇原創(chuàng)分享
          作者 l Hollis
          來源 l Hollis(ID:hollischuang)
          在日常開發(fā)中,我們經(jīng)常需要給對象進(jìn)行賦值,通常會調(diào)用其set/get方法,有些時(shí)候,如果我們要轉(zhuǎn)換的兩個對象之間屬性大致相同,會考慮使用屬性拷貝工具進(jìn)行。
          如我們經(jīng)常在代碼中會對一個數(shù)據(jù)結(jié)構(gòu)封裝成DO、SDO、DTO、VO等,而這些Bean中的大部分屬性都是一樣的,所以使用屬性拷貝類工具可以幫助我們節(jié)省大量的set和get操作。
          市面上有很多類似的工具類,比較常用的有
          1、Spring BeanUtils?
          2、Cglib BeanCopier?
          3、Apache BeanUtils?
          4、Apache PropertyUtils?
          5、Dozer
          那么,我們到底應(yīng)該選擇哪種工具類更加合適呢?為什么阿里巴巴Java開發(fā)手冊中提到禁止使用Apache BeanUtils呢?
          ?由于篇幅優(yōu)先,關(guān)于這幾種工具類的用法及區(qū)別,還有到底是什么是淺拷貝和深拷貝不在本文的討論范圍內(nèi)。
          本文主要聚焦于對比這幾個類庫的性能問題。



          性能對比
          No Data No BB,我們就來寫代碼來對比下這幾種框架的性能情況。
          代碼示例如下:
          首先定義一個PersonDO類:
          public?class?PersonDO?{

          ????private?Integer?id;

          ????private?String?name;

          ????private?Integer?age;

          ????private?Date?birthday;

          ????//省略setter/getter

          }
          再定義一個PersonDTO類:
          public?class?PersonDTO?{

          ????private?String?name;

          ????private?Integer?age;

          ????private?Date?birthday;

          }
          然后進(jìn)行測試類的編寫:
          使用Spring BeanUtils進(jìn)行屬性拷貝:

          private?void?mappingBySpringBeanUtils(PersonDO?personDO,?int?times)?{

          ????StopWatch?stopwatch?=?new?StopWatch();

          ????stopwatch.start();


          ????for?(int?i?=?0;?i?
          ????????PersonDTO?personDTO?=?new?PersonDTO();

          ????????org.springframework.beans.BeanUtils.copyProperties(personDO,?personDTO);

          ????}

          ????stopwatch.stop();

          ????System.out.println("mappingBySpringBeanUtils?cost?:"?+?stopwatch.getTotalTimeMillis());

          }

          其中的StopWatch用于記錄代碼執(zhí)行時(shí)間,方便進(jìn)行對比。
          使用Cglib BeanCopier進(jìn)行屬性拷貝:

          private?void?mappingByCglibBeanCopier(PersonDO?personDO,?int?times)?{

          ????StopWatch?stopwatch?=?new?StopWatch();

          ????stopwatch.start();

          ????for?(int?i?=?0;?i?
          ????????PersonDTO?personDTO?=?new?PersonDTO();

          ????????BeanCopier?copier?=?BeanCopier.create(PersonDO.class,?PersonDTO.class,?false);

          ????????copier.copy(personDO,?personDTO,?null);

          ????}

          ????stopwatch.stop();

          ????System.out.println("mappingByCglibBeanCopier?cost?:"?+?stopwatch.getTotalTimeMillis());

          }

          使用Apache BeanUtils進(jìn)行屬性拷貝:

          private?void?mappingByApacheBeanUtils(PersonDO?personDO,?int?times)

          ????throws?InvocationTargetException,?IllegalAccessException?
          {

          ????StopWatch?stopwatch?=?new?StopWatch();

          ????stopwatch.start();

          ????for?(int?i?=?0;?i?
          ????????PersonDTO?personDTO?=?new?PersonDTO();

          ????????BeanUtils.copyProperties(personDTO,?personDO);

          ????}

          ????stopwatch.stop();

          ????System.out.println("mappingByApacheBeanUtils?cost?:"?+?stopwatch.getTotalTimeMillis());

          }

          使用Apache PropertyUtils進(jìn)行屬性拷貝:

          private?void?mappingByApachePropertyUtils(PersonDO?personDO,?int?times)

          ????throws?InvocationTargetException,?IllegalAccessException,?NoSuchMethodException?
          {

          ????StopWatch?stopwatch?=?new?StopWatch();

          ????stopwatch.start();

          ????for?(int?i?=?0;?i?
          ????????PersonDTO?personDTO?=?new?PersonDTO();

          ????????PropertyUtils.copyProperties(personDTO,?personDO);

          ????}

          ????stopwatch.stop();

          ????System.out.println("mappingByApachePropertyUtils?cost?:"?+?stopwatch.getTotalTimeMillis());

          }

          然后執(zhí)行以下代碼:

          public?static?void?main(String[]?args)

          ????throws?InvocationTargetException,?IllegalAccessException,?NoSuchMethodException?
          {

          ????PersonDO?personDO?=?new?PersonDO();

          ????personDO.setName("Hollis");

          ????personDO.setAge(26);

          ????personDO.setBirthday(new?Date());

          ????personDO.setId(1);


          ????MapperTest?mapperTest?=?new?MapperTest();


          ????mapperTest.mappingBySpringBeanUtils(personDO,?100);

          ????mapperTest.mappingBySpringBeanUtils(personDO,?1000);

          ????mapperTest.mappingBySpringBeanUtils(personDO,?10000);

          ????mapperTest.mappingBySpringBeanUtils(personDO,?100000);

          ????mapperTest.mappingBySpringBeanUtils(personDO,?1000000);

          ????mapperTest.mappingByCglibBeanCopier(personDO,?100);

          ????mapperTest.mappingByCglibBeanCopier(personDO,?1000);

          ????mapperTest.mappingByCglibBeanCopier(personDO,?10000);

          ????mapperTest.mappingByCglibBeanCopier(personDO,?100000);

          ????mapperTest.mappingByCglibBeanCopier(personDO,?1000000);

          ????mapperTest.mappingByApachePropertyUtils(personDO,?100);

          ????mapperTest.mappingByApachePropertyUtils(personDO,?1000);

          ????mapperTest.mappingByApachePropertyUtils(personDO,?10000);

          ????mapperTest.mappingByApachePropertyUtils(personDO,?100000);

          ????mapperTest.mappingByApachePropertyUtils(personDO,?1000000);

          ????mapperTest.mappingByApacheBeanUtils(personDO,?100);

          ????mapperTest.mappingByApacheBeanUtils(personDO,?1000);

          ????mapperTest.mappingByApacheBeanUtils(personDO,?10000);

          ????mapperTest.mappingByApacheBeanUtils(personDO,?100000);

          ????mapperTest.mappingByApacheBeanUtils(personDO,?1000000);

          }

          得到結(jié)果如下:
          工具類執(zhí)行1000次耗時(shí)執(zhí)行10000次耗時(shí)執(zhí)行100000次耗時(shí)執(zhí)行1000000次耗時(shí)
          Spring BeanUtils5ms10ms45ms169ms
          Cglib BeanCopier4ms18ms45ms91ms
          Apache PropertyUtils60ms265ms1444ms11492ms
          Apache BeanUtils138ms816ms4154ms36938ms
          Dozer566ms2254ms11136ms102965ms

          畫了一張折線圖更方便大家進(jìn)行對比

          綜上,我們基本可以得出結(jié)論,在性能方面,Spring BeanUtils和Cglib BeanCopier表現(xiàn)比較不錯,而Apache PropertyUtils、Apache BeanUtils以及Dozer則表現(xiàn)的很不好。
          所以,如果考慮性能情況的話,建議大家不要選擇Apache PropertyUtils、Apache BeanUtils以及Dozer等工具類。
          很多人會不理解,為什么大名鼎鼎的Apache開源出來的的類庫性能確不高呢?這不像是Apache的風(fēng)格呀,這背后導(dǎo)致性能低下的原因又是什么呢?
          其實(shí),是因?yàn)锳pache BeanUtils力求做得完美, 在代碼中增加了非常多的校驗(yàn)、兼容、日志打印等代碼,過度的包裝導(dǎo)致性能下降嚴(yán)重。



          總結(jié)
          本文通過對比幾種常見的屬性拷貝的類庫,分析得出了這些工具類的性能情況,最終也驗(yàn)證了《阿里巴巴Java開發(fā)手冊》中提到的"Apache BeanUtils 效率低"的事實(shí)。
          但是本文只是站在性能這一單一角度進(jìn)行了對比,我們在選擇一個工具類的時(shí)候還會有其他方面的考慮,比如使用成本、理解難度、兼容性、可擴(kuò)展性等,對于這種拷貝類工具類,我們還會考慮其功能是否完善等。
          就像雖然Dozer性能比較差,但是他可以很好的和Spring結(jié)合,可以通過配置文件等進(jìn)行屬性之間的映射等,也受到了很多開發(fā)者的喜愛。
          本文用到的第三方類庫的maven依賴如下:



          <dependency>

          ????<groupId>commons-beanutilsgroupId>


          ????<artifactId>commons-beanutilsartifactId>

          ????<version>1.9.4version>

          dependency>



          <dependency>

          ????<groupId>commons-logginggroupId>

          ????<artifactId>commons-loggingartifactId>

          ????<version>1.1.2version>

          dependency>





          <dependency>

          ????<groupId>org.springframeworkgroupId>

          ????<artifactId>org.springframework.beansartifactId>

          ????<version>3.1.1.RELEASEversion>

          dependency>





          <dependency>

          ????<groupId>cglibgroupId>

          ????<artifactId>cglib-nodepartifactId>

          ????<version>2.2.2version>

          dependency>





          <dependency>

          ????<groupId>net.sf.dozergroupId>

          ????<artifactId>dozerartifactId>

          ????<version>5.5.1version>

          dependency>





          <dependency>

          ????<groupId>org.slf4jgroupId>

          ????<artifactId>slf4j-apiartifactId>

          ????<version>1.7.7version>

          dependency>



          <dependency>

          ????<groupId>org.slf4jgroupId>

          ????<artifactId>jul-to-slf4jartifactId>

          ????<version>1.7.7version>

          dependency>



          <dependency>

          ????<groupId>org.slf4jgroupId>

          ????<artifactId>jcl-over-slf4jartifactId>

          ????<version>1.7.7version>

          dependency>



          <dependency>

          ????<groupId>org.slf4jgroupId>

          ????<artifactId>log4j-over-slf4jartifactId>

          ????<version>1.7.7version>

          dependency>



          <dependency>

          ????<groupId>org.slf4jgroupId>

          ????<artifactId>slf4j-jdk14artifactId>

          ????<version>1.7.7version>

          dependency>



          關(guān)于作者Hollis(ID:hollischuang),一個對Coding有著獨(dú)特追求的人,現(xiàn)任阿里巴巴技術(shù)專家,個人技術(shù)博主,技術(shù)文章全網(wǎng)閱讀量數(shù)千萬,《程序員的三門課》聯(lián)合作者。


          往期推薦

          阿里的簡歷多久可以投遞一次?次數(shù)多了有沒有影響?可以同時(shí)進(jìn)行嗎?


          什么是a站、b站、c站、d站、e站、f站、g站、h站、i站、j站、k站、l站、m站、n站…z站?


          一口氣說出 4 種分布式一致性 Session 實(shí)現(xiàn)方式,面試杠杠的~


          ?

          直面Java第329期:哪個命令可以監(jiān)控虛擬機(jī)各種運(yùn)行狀態(tài)信息?

          深入并發(fā)第013期:拓展synchronized——鎖優(yōu)化


          如果你喜歡本文,

          請長按二維碼,關(guān)注?Hollis.

          轉(zhuǎn)發(fā)至朋友圈,是對我最大的支持。


          點(diǎn)個?在看?
          喜歡是一種感覺
          在看是一種支持
          ↘↘↘
          瀏覽 22
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国内视频一区 | 内射视频福利 | 秋霞丝鲁片一区二区三区手机在绒免 | 日韩无码乱伦小说 | 伊伊色综合|