1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        兩難!到底用Apache BeanUtils還是Spring BeanUtils?

        共 7871字,需瀏覽 16分鐘

         ·

        2020-08-28 01:11

        來(lái)源 |?https://urlify.cn/vUfIry

        其實(shí)在用Assert、或者一些StringUtils的時(shí)候我經(jīng)常不知道應(yīng)該用Apache的還是用Spring,好像都能滿足我要求,性能方面還真是想得少,來(lái)看看這篇文章,對(duì)比對(duì)比~

        在我們實(shí)際項(xiàng)目開(kāi)發(fā)過(guò)程中,我們經(jīng)常需要將不同的兩個(gè)對(duì)象實(shí)例進(jìn)行屬性復(fù)制,從而基于源對(duì)象的屬性信息進(jìn)行后續(xù)操作,而不改變?cè)磳?duì)象的屬性信息, 比如 DTO 數(shù)據(jù)傳輸對(duì)象和數(shù)據(jù)對(duì)象 DO,我們需要將 DO 對(duì)象進(jìn)行屬性復(fù)制到 DTO,但是對(duì)象格式又不一樣,所以我們需要編寫(xiě)映射代碼將對(duì)象中的屬性值從一種類型轉(zhuǎn)換成另一種類型。

        對(duì)象拷貝

        在具體介紹兩種 BeanUtils 之前,先來(lái)補(bǔ)充一些基礎(chǔ)知識(shí)。它們兩種工具本質(zhì)上就是對(duì)象拷貝工具,而對(duì)象拷貝又分為深拷貝和淺拷貝,下面進(jìn)行詳細(xì)解釋。

        什么是淺拷貝和深拷貝

        在 Java 中,除了 基本數(shù)據(jù)類型之外,還存在 類的實(shí)例對(duì)象這個(gè)引用數(shù)據(jù)類型,而一般使用 “=” 號(hào)做賦值操作的時(shí)候,對(duì)于基本數(shù)據(jù)類型,實(shí)際上是拷貝的它的值,但是對(duì)于對(duì)象而言,其實(shí)賦值的只是這個(gè)對(duì)象的引用,將原對(duì)象的引用傳遞過(guò)去,他們實(shí)際還是指向的同一個(gè)對(duì)象。而淺拷貝和深拷貝就是在這個(gè)基礎(chǔ)上做的區(qū)分,如果在拷貝這個(gè)對(duì)象的時(shí)候,只對(duì)基本數(shù)據(jù)類型進(jìn)行了拷貝,而對(duì)引用數(shù)據(jù)類型只是進(jìn)行引用的傳遞,而沒(méi)有真實(shí)的創(chuàng)建一個(gè)新的對(duì)象,則認(rèn)為是淺拷貝。反之,在對(duì)引用數(shù)據(jù)類型進(jìn)行拷貝的時(shí)候,創(chuàng)建了一個(gè)新的對(duì)象,并且復(fù)制其內(nèi)的成員變量,則認(rèn)為是深拷貝。

        搜索公縱號(hào):MarkerHub,關(guān)注回復(fù)[?vue?]獲取前后端入門(mén)教程!

        簡(jiǎn)單來(lái)說(shuō):

        • 淺拷貝:對(duì)基本數(shù)據(jù)類型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類型進(jìn)行引用傳遞般的拷貝,此為淺拷貝

        • 深拷貝:對(duì)基本數(shù)據(jù)類型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類型,創(chuàng)建一個(gè)新的對(duì)象,并復(fù)制其內(nèi)容,此為深拷貝。

        BeanUtils

        前面簡(jiǎn)單講了一下對(duì)象拷貝的一些知識(shí),下面就來(lái)具體看下兩種 BeanUtils 工具

        Apache 的 BeanUtils

        首先來(lái)看一個(gè)非常簡(jiǎn)單的 BeanUtils 的例子

        publicclass?PersonSource?{
        ????private?Integer?id;
        ????private?String?username;
        ????private?String?password;
        ????private?Integer?age;
        ????//?getters/setters?omiited
        }
        publicclass?PersonDest?{
        ????private?Integer?id;
        ????private?String?username;
        ????private?Integer?age;
        ????//?getters/setters?omiited
        }
        publicclass?TestApacheBeanUtils?{
        ????public?static?void?main(String[]?args)?throws?InvocationTargetException,?IllegalAccessException?{
        ???????//下面只是用于單獨(dú)測(cè)試
        ????????PersonSource?personSource?=?new?PersonSource(1,?"pjmike",?"12345",?21);
        ????????PersonDest?personDest?=?new?PersonDest();
        ????????BeanUtils.copyProperties(personDest,personSource);
        ????????System.out.println("persondest:?"+personDest);
        ????}
        }
        persondest:?PersonDest{id=1,?username='pjmike',?age=21}


        從上面的例子可以看出,對(duì)象拷貝非常簡(jiǎn)單,BeanUtils 最常用的方法就是:

        //將源對(duì)象中的值拷貝到目標(biāo)對(duì)象//將源對(duì)象中的值拷貝到目標(biāo)對(duì)象
        public?static?void?copyProperties(Object?dest,?Object?orig)?throws?IllegalAccessException,?InvocationTargetException?{
        ????BeanUtilsBean.getInstance().copyProperties(dest,?orig);
        }

        默認(rèn)情況下,使用 org.apache.commons.beanutils.BeanUtils 對(duì)復(fù)雜對(duì)象的復(fù)制是引用,這是一種淺拷貝

        但是由于 Apache 下的 BeanUtils 對(duì)象拷貝性能太差,不建議使用,而且在阿里巴巴 Java 開(kāi)發(fā)規(guī)約插件上也明確指出:

        Ali-Check | 避免用 Apache Beanutils 進(jìn)行屬性的 copy。

        commons-beantutils 對(duì)于對(duì)象拷貝加了很多的檢驗(yàn),包括類型的轉(zhuǎn)換,甚至還會(huì)檢驗(yàn)對(duì)象所屬的類的可訪問(wèn)性, 可謂相當(dāng)復(fù)雜,這也造就了它的差勁的性能,具體實(shí)現(xiàn)代碼如下:

        public?void?copyProperties(final?Object?dest,?final?Object?orig)
        ????????throws?IllegalAccessException,?InvocationTargetException?
        {

        ????????//?Validate?existence?of?the?specified?beans
        ????????if?(dest?==?null)?{
        ????????????thrownew?IllegalArgumentException
        ????????????????????("No?destination?bean?specified")
        ;
        ????????}
        ????????if?(orig?==?null)?{
        ????????????thrownew?IllegalArgumentException("No?origin?bean?specified");
        ????????}
        ????????if?(log.isDebugEnabled())?{
        ????????????log.debug("BeanUtils.copyProperties("?+?dest?+?",?"?+
        ??????????????????????orig?+?")");
        ????????}

        ????????//?Copy?the?properties,?converting?as?necessary
        ????????if?(orig?instanceof?DynaBean)?{
        ????????????final?DynaProperty[]?origDescriptors?=
        ????????????????((DynaBean)?orig).getDynaClass().getDynaProperties();
        ????????????for?(DynaProperty?origDescriptor?:?origDescriptors)?{
        ????????????????final?String?name?=?origDescriptor.getName();
        ????????????????//?Need?to?check?isReadable()?for?WrapDynaBean
        ????????????????//?(see?Jira?issue#?BEANUTILS-61)
        ????????????????if?(getPropertyUtils().isReadable(orig,?name)?&&
        ????????????????????getPropertyUtils().isWriteable(dest,?name))?{
        ????????????????????final?Object?value?=?((DynaBean)?orig).get(name);
        ????????????????????copyProperty(dest,?name,?value);
        ????????????????}
        ????????????}
        ????????}?elseif?(orig?instanceof?Map)?{
        ????????????@SuppressWarnings("unchecked")
        ????????????final
        ????????????//?Map?properties?are?always?of?type?
        ????????????Map?propMap?=?(Map)?orig;
        ????????????for?(final?Map.Entry?entry?:?propMap.entrySet())?{
        ????????????????final?String?name?=?entry.getKey();
        ????????????????if?(getPropertyUtils().isWriteable(dest,?name))?{
        ????????????????????copyProperty(dest,?name,?entry.getValue());
        ????????????????}
        ????????????}
        ????????}?else/*?if?(orig?is?a?standard?JavaBean)?*/?{
        ????????????final?PropertyDescriptor[]?origDescriptors?=
        ????????????????getPropertyUtils().getPropertyDescriptors(orig);
        ????????????for?(PropertyDescriptor?origDescriptor?:?origDescriptors)?{
        ????????????????final?String?name?=?origDescriptor.getName();
        ????????????????if?("class".equals(name))?{
        ????????????????????continue;?//?No?point?in?trying?to?set?an?object's?class
        ????????????????}
        ????????????????if?(getPropertyUtils().isReadable(orig,?name)?&&
        ????????????????????getPropertyUtils().isWriteable(dest,?name))?{
        ????????????????????try?{
        ????????????????????????final?Object?value?=
        ????????????????????????????getPropertyUtils().getSimpleProperty(orig,?name);
        ????????????????????????copyProperty(dest,?name,?value);
        ????????????????????}?catch?(final?NoSuchMethodException?e)?{
        ????????????????????????//?Should?not?happen
        ????????????????????}
        ????????????????}
        ????????????}
        ????????}

        ????}

        Spring 的 BeanUtils

        使用 spring 的 BeanUtils 進(jìn)行對(duì)象拷貝:

        publicclass?TestSpringBeanUtils?{
        ????public?static?void?main(String[]?args)?throws?InvocationTargetException,?IllegalAccessException?{

        ???????//下面只是用于單獨(dú)測(cè)試
        ????????PersonSource?personSource?=?new?PersonSource(1,?"pjmike",?"12345",?21);
        ????????PersonDest?personDest?=?new?PersonDest();
        ????????BeanUtils.copyProperties(personSource,personDest);
        ????????System.out.println("persondest:?"+personDest);
        ????}
        }

        Spring 下的 BeanUtils 也是使用 copyProperties 方法進(jìn)行拷貝,只不過(guò)它的實(shí)現(xiàn)方式非常簡(jiǎn)單,就是對(duì)兩個(gè)對(duì)象中相同名字的屬性進(jìn)行簡(jiǎn)單的 get/set,僅檢查屬性的可訪問(wèn)性。具體實(shí)現(xiàn)如下:

        private?static?void?copyProperties(Object?source,?Object?target,?@Nullable?Class?editable,
        ??????@Nullable?String...?ignoreProperties)
        ?throws?BeansException?
        {

        ????Assert.notNull(source,?"Source?must?not?be?null");
        ????Assert.notNull(target,?"Target?must?not?be?null");

        ????Class?actualEditable?=?target.getClass();
        ????if?(editable?!=?null)?{
        ??????if?(!editable.isInstance(target))?{
        ????????throw?new?IllegalArgumentException("Target?class?["?+?target.getClass().getName()?+
        ????????????"]?not?assignable?to?Editable?class?["?+?editable.getName()?+?"]");
        ??????}
        ??????actualEditable?=?editable;
        ????}
        ????PropertyDescriptor[]?targetPds?=?getPropertyDescriptors(actualEditable);
        ????List?ignoreList?=?(ignoreProperties?!=?null???Arrays.asList(ignoreProperties)?:?null);

        ????for?(PropertyDescriptor?targetPd?:?targetPds)?{
        ??????Method?writeMethod?=?targetPd.getWriteMethod();
        ??????if?(writeMethod?!=?null?&&?(ignoreList?==?null?||?!ignoreList.contains(targetPd.getName())))?{
        ????????PropertyDescriptor?sourcePd?=?getPropertyDescriptor(source.getClass(),?targetPd.getName());
        ????????if?(sourcePd?!=?null)?{
        ??????????Method?readMethod?=?sourcePd.getReadMethod();
        ??????????if?(readMethod?!=?null?&&
        ??????????????ClassUtils.isAssignable(writeMethod.getParameterTypes()[0],?readMethod.getReturnType()))?{
        ????????????try?{
        ??????????????if?(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()))?{
        ????????????????readMethod.setAccessible(true);
        ??????????????}
        ??????????????Object?value?=?readMethod.invoke(source);
        ??????????????if?(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()))?{
        ????????????????writeMethod.setAccessible(true);
        ??????????????}
        ??????????????writeMethod.invoke(target,?value);
        ????????????}
        ????????????catch?(Throwable?ex)?{
        ??????????????throw?new?FatalBeanException(
        ??????????????????"Could?not?copy?property?'"?+?targetPd.getName()?+?"'?from?source?to?target",?ex);
        ????????????}
        ??????????}
        ????????}
        ??????}
        ????}
        ??}

        可以看到,成員變量賦值是基于目標(biāo)對(duì)象的成員列表,并且會(huì)跳過(guò) ignore 的以及在源對(duì)象中不存在,所以這個(gè)方法是安全的,不會(huì)因?yàn)閮蓚€(gè)對(duì)象之間的結(jié)構(gòu)差異導(dǎo)致錯(cuò)誤,但是必須保證同名的兩個(gè)成員變量類型相同

        小結(jié)

        以上簡(jiǎn)要的分析兩種 BeanUtils,因?yàn)?Apache 下的 BeanUtils 性能較差,不建議使用,可以使用 Spring 的 BeanUtils ,或者使用其他拷貝框架,比如:Dozer、ModelMapper 等等


        - END -


        1.??Spring的Controller是單例還是多例?怎么保證并發(fā)的安全

        2.??京東把 Elasticsearch 用得真牛逼!日均5億訂單查詢完美解決!

        3.??開(kāi)學(xué)啦|當(dāng)當(dāng)花160買(mǎi)400好書(shū)

        之前博主分享了很多資源,有的已經(jīng)刪除了(你懂得),如果有的你當(dāng)時(shí)沒(méi)有領(lǐng)到還想領(lǐng)得就可以加我微信,我在發(fā)給你,你需要得資源也可以給我說(shuō),我盡力給你找~


        ? ?回復(fù)"谷谷”獲取

        Java開(kāi)發(fā)大型電商系統(tǒng)商城實(shí)戰(zhàn)視頻教程


        好文章,我在看

        瀏覽 73
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            97超碰成人网 | 久久久久有精品国产白浆天美传媒 | 五月伊人激情 | chinese麻豆videostube | 色婷婷在线视频观看 | 二级黄色 | 国产区欧美 | 宝贝放松点别夹h | 五月婷综合 | 日毛片 |