2020-07-29 為什么阿里巴巴禁止使用Apache Beanutils進行屬性的copy逮走?

引出問題

在日常開發(fā)中鸠蚪,我們經(jīng)常需要給對象進行賦值,通常會調(diào)用其set/get方法,有些時候茅信,如果我們要轉(zhuǎ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呢?

阿里巴巴手冊

性能對比


實體類1


實體類2

測試代碼:

package com.example.demo.bussniss.entity;

import org.apache.commons.beanutils.PropertyUtils;

import org.springframework.beans.BeanUtils;

import org.springframework.cglib.beans.BeanCopier;

import org.springframework.util.StopWatch;

import java.lang.reflect.InvocationTargetException;

import java.util.Date;

/**

* @author :suyanlong

* @date :Created in 2020/7/30 9:29

* @description:ceshi

* @version: 1.0

*/

public class PersonTest {

// 使用Spring BeanUtils進行屬性拷貝:

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

StopWatch stopwatch =new StopWatch();

? ? ? ? stopwatch.start();

? ? ? ? for (int i =0; i < times; i++) {

PersonDTO personDTO =new PersonDTO();

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

? ? ? ? }

stopwatch.stop();

? ? ? ? System.out.println("spring copy time:" + stopwatch.getTotalTimeMillis());

? ? }

// 使用Cglib BeanCopier進行屬性拷貝:

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

StopWatch stopwatch =new StopWatch();

? ? ? ? stopwatch.start();

? ? ? ? for (int i =0; i < times; i++) {

PersonDTO personDTO =new PersonDTO();

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

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

? ? ? ? }

stopwatch.stop();

? ? ? ? System.out.println("cglibs copy time:" + stopwatch.getTotalTimeMillis());

? ? }

// 使用Apache BeanUtils進行屬性拷貝:

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

throws InvocationTargetException, IllegalAccessException {

StopWatch stopwatch =new StopWatch();

? ? ? ? stopwatch.start();

? ? ? ? for (int i =0; i < times; i++) {

PersonDTO personDTO =new PersonDTO();

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

? ? ? ? }

stopwatch.stop();

? ? ? ? System.out.println("apbean copy time:" + stopwatch.getTotalTimeMillis());

? ? }

// 使用Apache PropertyUtils進行屬性拷貝:

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

throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

StopWatch stopwatch =new StopWatch();

? ? ? ? stopwatch.start();

? ? ? ? for (int i =0; i < times; i++) {

PersonDTO personDTO =new PersonDTO();

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

? ? ? ? }

stopwatch.stop();

? ? ? ? System.out.println("approp copy time:" + stopwatch.getTotalTimeMillis());

? ? }

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);

? ? ? ? PersonTest mapperTest =new PersonTest();

? ? ? ? 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é)果

測試結(jié)果

綜上吧秕,我們基本可以得出結(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)致性能低下的原因又是什么呢霎奢?

其實,是因為Apache BeanUtils力求做得完美, 在代碼中增加了非常多的校驗饼灿、兼容幕侠、日志打印等代碼,過度的包裝導(dǎo)致性能下降嚴(yán)重碍彭。

總結(jié)

本文通過對比幾種常見的屬性拷貝的類庫晤硕,分析得出了這些工具類的性能情況悼潭,最終也驗證了《阿里巴巴Java開發(fā)手冊》中提到的"Apache BeanUtils 效率低"的事實。

但是本文只是站在性能這一單一角度進行了對比舞箍,我們在選擇一個工具類的時候還會有其他方面的考慮舰褪,比如使用成本、理解難度疏橄、兼容性抵知、可擴展性等,對于這種拷貝類工具類软族,我們還會考慮其功能是否完善等。

就像雖然Dozer性能比較差残制,但是他可以很好的和Spring結(jié)合立砸,可以通過配置文件等進行屬性之間的映射等,也受到了很多開發(fā)者的喜愛初茶。

深拷貝颗祝、淺拷貝參考:https://blog.csdn.net/weixin_39585051/article/details/107681667


參考:https://mp.weixin.qq.com/s/PxRnZ6rMVxMf4FksvjIvtA

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恼布,隨后出現(xiàn)的幾起案子螺戳,更是在濱河造成了極大的恐慌,老刑警劉巖折汞,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倔幼,死亡現(xiàn)場離奇詭異,居然都是意外死亡爽待,警方通過查閱死者的電腦和手機损同,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鸟款,“玉大人膏燃,你說我怎么就攤上這事『问玻” “怎么了组哩?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長处渣。 經(jīng)常有香客問我伶贰,道長,這世上最難降的妖魔是什么罐栈? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任幕袱,我火速辦了婚禮,結(jié)果婚禮上悠瞬,老公的妹妹穿的比我還像新娘们豌。我一直安慰自己涯捻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布望迎。 她就那樣靜靜地躺著障癌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辩尊。 梳的紋絲不亂的頭發(fā)上涛浙,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音摄欲,去河邊找鬼轿亮。 笑死,一個胖子當(dāng)著我的面吹牛胸墙,可吹牛的內(nèi)容都是我干的我注。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼迟隅,長吁一口氣:“原來是場噩夢啊……” “哼但骨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起智袭,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤奔缠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吼野,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體校哎,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年瞳步,在試婚紗的時候發(fā)現(xiàn)自己被綠了贬蛙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡谚攒,死狀恐怖阳准,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情馏臭,我是刑警寧澤野蝇,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站括儒,受9級特大地震影響绕沈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帮寻,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一乍狐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧固逗,春花似錦浅蚪、人聲如沸藕帜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洽故。三九已至,卻和暖如春盗誊,著一層夾襖步出監(jiān)牢的瞬間时甚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工哈踱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留荒适,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓开镣,卻偏偏與公主長得像刀诬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哑子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361