<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還是Spring BeanUtils?

          共 7544字,需瀏覽 16分鐘

           ·

          2020-08-15 10:36

          ? ? ?

          ? ?正文? ?

          在我們實(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ì)象中的屬性值從一種類(lèi)型轉(zhuǎn)換成另一種類(lèi)型。

          對(duì)象拷貝

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

          什么是淺拷貝和深拷貝

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

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

          • 淺拷貝:對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類(lèi)型進(jìn)行引用傳遞般的拷貝,此為淺拷貝
          • 深拷貝:對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類(lèi)型,創(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),包括類(lèi)型的轉(zhuǎn)換,甚至還會(huì)檢驗(yàn)對(duì)象所屬的類(lèi)的可訪問(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è)成員變量類(lèi)型相同

          小結(jié)

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


          轉(zhuǎn)載公眾號(hào):程序員小樂(lè)

          版權(quán)申明:內(nèi)容來(lái)源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無(wú)法確認(rèn),我們都會(huì)標(biāo)明作者及出處,如有侵權(quán)煩請(qǐng)告知,我們會(huì)立即刪除并表示歉意。謝謝!





          感謝閱讀



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

          手機(jī)掃一掃分享

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

          手機(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>
                  亚洲vo1 | 四虎欧美性爱视频免费播放 | 一级片黄色电影在线观看 | 青青草视频手机华人 | 日B小视频 |