新聞中心
在日常開發(fā)中,我們經(jīng)常需要給對(duì)象進(jìn)行賦值,通常會(huì)調(diào)用其set/get方法,有些時(shí)候,如果我們要轉(zhuǎn)換的兩個(gè)對(duì)象之間屬性大致相同,會(huì)考慮使用屬性拷貝工具進(jìn)行。

創(chuàng)新互聯(lián)是一家專業(yè)提供陵川企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司、H5開發(fā)、小程序制作等業(yè)務(wù)。10年已為陵川眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
如我們經(jīng)常在代碼中會(huì)對(duì)一個(gè)數(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ōu)先,關(guān)于這幾種工具類的用法及區(qū)別,還有到底是什么是淺拷貝和深拷貝不在本文的討論范圍內(nèi)。本文主要聚焦于對(duì)比這幾個(gè)類庫(kù)的性能問(wèn)題。
性能對(duì)比
No Data No BB,我們就來(lái)寫代碼來(lái)對(duì)比下這幾種框架的性能情況。代碼示例如下:首先定義一個(gè)PersonDO類:
- public class PersonDO {
- private Integer id;
- private String name;
- private Integer age;
- private Date birthday;
- //省略setter/getter
- }
再定義一個(gè)PersonDTO類:
- public class PersonDTO {
- private String name;
- private Integer age;
- private Date birthday;
- }
然后進(jìn)行測(cè)試類的編寫:使用Spring BeanUtils進(jìn)行屬性拷貝:
- 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("mappingBySpringBeanUtils cost :" + stopwatch.getTotalTimeMillis());
- }
其中的StopWatch用于記錄代碼執(zhí)行時(shí)間,方便進(jìn)行對(duì)比。
使用Cglib BeanCopier進(jìn)行屬性拷貝:
- 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("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 < times; 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 < times; 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 BeanUtils | 5ms | 10ms | 45ms | 169ms |
| Cglib BeanCopier | 4ms | 18ms | 45ms | 91ms |
| Apache PropertyUtils | 60ms | 265ms | 1444ms | 11492ms |
| Apache BeanUtils | 138ms | 816ms | 4154ms | 36938ms |
| Dozer | 566ms | 2254ms | 11136ms | 102965ms |
畫了一張折線圖更方便大家進(jìn)行對(duì)比
綜上,我們基本可以得出結(jié)論,在性能方面,Spring BeanUtils和Cglib BeanCopier表現(xiàn)比較不錯(cuò),而Apache PropertyUtils、Apache BeanUtils以及Dozer則表現(xiàn)的很不好。
所以,如果考慮性能情況的話,建議大家不要選擇Apache PropertyUtils、Apache BeanUtils以及Dozer等工具類。很多人會(huì)不理解,為什么大名鼎鼎的Apache開源出來(lái)的的類庫(kù)性能確不高呢?這不像是Apache的風(fēng)格呀,這背后導(dǎo)致性能低下的原因又是什么呢?其實(shí),是因?yàn)锳pache BeanUtils力求做得完美, 在代碼中增加了非常多的校驗(yàn)、兼容、日志打印等代碼,過(guò)度的包裝導(dǎo)致性能下降嚴(yán)重。
總結(jié)
本文通過(guò)對(duì)比幾種常見的屬性拷貝的類庫(kù),分析得出了這些工具類的性能情況,最終也驗(yàn)證了《阿里巴巴Java開發(fā)手冊(cè)》中提到的"Apache BeanUtils 效率低"的事實(shí)。
但是本文只是站在性能這一單一角度進(jìn)行了對(duì)比,我們?cè)谶x擇一個(gè)工具類的時(shí)候還會(huì)有其他方面的考慮,比如使用成本、理解難度、兼容性、可擴(kuò)展性等,對(duì)于這種拷貝類工具類,我們還會(huì)考慮其功能是否完善等。
就像雖然Dozer性能比較差,但是他可以很好的和Spring結(jié)合,可以通過(guò)配置文件等進(jìn)行屬性之間的映射等,也受到了很多開發(fā)者的喜愛。
本文用到的第三方類庫(kù)的maven依賴如下:
commons-beanutils commons-beanutils 1.9.4 commons-logging commons-logging 1.1.2 org.springframework org.springframework.beans 3.1.1.RELEASE cglib cglib-nodep 2.2.2 net.sf.dozer dozer 5.5.1 org.slf4j slf4j-api 1.7.7 org.slf4j jul-to-slf4j 1.7.7 org.slf4j jcl-over-slf4j 1.7.7 org.slf4j log4j-over-slf4j 1.7.7 org.slf4j slf4j-jdk14 1.7.7
分享文章:為什么阿里巴巴禁止使用ApacheBeanutils進(jìn)行屬性的Copy?
分享路徑:http://www.dlmjj.cn/article/djdhies.html


咨詢
建站咨詢
