偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

六種常用Bean拷貝工具一覽

開(kāi)發(fā) 后端
隨著業(yè)務(wù)的劃分越來(lái)越細(xì),對(duì)象的拷貝工作也越來(lái)越頻繁,所以本文就來(lái)梳理一下常用的對(duì)象拷貝工具和它們的差異。

[[439335]]

 在我們?nèi)粘5墓ぷ髦?,?jīng)常需要做對(duì)象的拷貝或轉(zhuǎn)化,例如在傳遞參數(shù)時(shí),把入?yún)⒌腄TO轉(zhuǎn)化為PO存入數(shù)據(jù)庫(kù),在返回前端時(shí)把PO再轉(zhuǎn)化為VO。如果再分的細(xì)一點(diǎn),可能還會(huì)有DO(Domain Object),TO(Transfer Object) ,BO(business object)等對(duì)象,隨著業(yè)務(wù)的劃分越來(lái)越細(xì),對(duì)象的拷貝工作也越來(lái)越頻繁,所以本文就來(lái)梳理一下常用的對(duì)象拷貝工具和它們的差異。

常用的工具大概有以下幾種:

  •  Apache BeanUtils 
  •  Spring BeanUtils
  •  cglib BeanCopier
  •  Hutool BeanUtil
  •  Mapstruct
  •  Dozer

準(zhǔn)備工作,創(chuàng)建兩個(gè)類PO和DTO: 

  1. @Data  
  2. public class OrderPO {  
  3.     Integer id;  
  4.     String orderNumber;  
  5.     List<String> proId;  
  6.  
  7. @Data  
  8. public class OrderDTO {  
  9.     int id;  
  10.     String orderNumber;  
  11.     List<String> proId;  

01.Apache  BeanUtils

引入依賴坐標(biāo): 

  1. <dependency>  
  2.     <groupId>commons-beanutils</groupId>  
  3.     <artifactId>commons-beanutils</artifactId>  
  4.     <version>1.9.3</version> 
  5.  </dependency> 

進(jìn)行測(cè)試,初始化PO對(duì)象,并創(chuàng)建DTO空對(duì)象,使用BeanUtils進(jìn)行: 

  1. @org.junit.Test  
  2. public void test(){  
  3.     OrderPO orderPO=new OrderPO();  
  4.     orderPO.setId(1);  
  5.     orderPO.setOrderNumber("orderNumber"); 
  6.     ArrayList<String> list = new ArrayList<String>() {{  
  7.         add("1");  
  8.         add("2");  
  9.     }};  
  10.     orderPO.setProId(list);  
  11.     OrderDTO orderDTO=new OrderDTO();  
  12.     BeanUtils.copyProperties(orderDTO,orderPO);  

打印兩個(gè)對(duì)象,具有相同的屬性: 

  1. OrderPO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2])  
  2. OrderDTO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2]) 

可以看出,在Bean中具有相同名稱的屬性分別是基本數(shù)據(jù)類型和包裝類時(shí),比如分別是int和Integer時(shí),可以正常進(jìn)行拷貝。那么再深究一點(diǎn),拷貝Bean過(guò)程中,使用的是深拷貝還是淺拷貝呢?

兩個(gè)List對(duì)象使用的是同一個(gè)對(duì)象,因此在拷貝中,如果存在引用對(duì)象,那么使用的是淺拷貝。在完成拷貝后,如果再修改這個(gè)對(duì)象: 

  1. list.add("3");  
  2. log.info(orderDTO.getProId()); 

再次打印DTO對(duì)象,發(fā)現(xiàn)即使不再次重新拷貝,修改的值也會(huì)被添加過(guò)去 

  1. OrderDTO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2, 3]) 

02.Spring  BeanUtils

如果使用的spring項(xiàng)目時(shí)不需要單獨(dú)引入依賴,單獨(dú)使用時(shí)需要引入坐標(biāo): 

  1. <dependency>  
  2.     <groupId>org.springframework</groupId>  
  3.     <artifactId>spring-beans</artifactId>  
  4.     <version>5.2.2.RELEASE</version>  
  5. </dependency> 

使用方式與apache的BeanUtils方法名相同,但參數(shù)順序相反,第一個(gè)參數(shù)是源對(duì)象,第二個(gè)參數(shù)是目標(biāo)對(duì)象: 

  1. BeanUtils.copyProperties(orderPO,orderDTO); 

過(guò)程省略,這里使用的還是淺拷貝。spring的BeanUtils還提供了額外的方法,這個(gè)可變參數(shù)的方法可以忽略某些屬性進(jìn)行拷貝: 

  1. void copyProperties(Object source, Object target, String... ignoreProperties); 

忽略orderNumber屬性進(jìn)行拷貝: 

  1. BeanUtils.copyProperties(orderPO,orderDTO,"orderNumber"); 

輸出結(jié)果: 

  1. OrderPO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2])  
  2. OrderDTO(id=1orderNumber=nullproId=[1, 2]) 

此外,在阿里巴巴的開(kāi)發(fā)手冊(cè)中,強(qiáng)制避免使用apache BeanUtils進(jìn)行拷貝,建議使用Spring BeanUtils或下面要介紹的BeanCopier。主要原因還是在于Spring并沒(méi)有與 apache一樣對(duì)反射做了過(guò)多校驗(yàn),另外Spring BeanUtils內(nèi)部使用了緩存,加快轉(zhuǎn)換的速度。此外,由于我們的大多項(xiàng)目已經(jīng)集成了Spring ,如果沒(méi)有其他特殊的需求,直接使用它的BeanUtils就能滿足我們的基本需求。

03.cglib  BeanCopier

如果工程內(nèi)含有spring-core包的依賴,也不需要額外引入依賴,否則需要引入坐標(biāo): 

  1. <dependency>  
  2.     <groupId>cglib</groupId>  
  3.     <artifactId>cglib</artifactId>  
  4.     <version>3.3.0</version>  
  5. </dependency> 

使用示例: 

  1. BeanCopier beanCopier = BeanCopier.create(  
  2.           orderPO.getClass(),   
  3.           orderDTO.getClass(), false);  
  4. beanCopier.copy(orderPO,orderDTO,null); 

測(cè)試結(jié)果: 

  1. OrderPO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2])  
  2. OrderDTO(id=0orderNumberorderNumber=orderNumber, proId=[1, 2]) 

在上面的例子中,id字段沒(méi)有被正??截?,兩個(gè)字段不同的是在PO中使用的是包裝類型Integer,但DTO中使用的是基本類型int。因此,使用BeanCopier時(shí),如果存在基本類型和包裝類,是無(wú)法被正常拷貝,改為相同類型后才能被正常拷貝。另外,BeanCopier使用的仍然是淺拷貝,驗(yàn)證過(guò)程大家可以自己進(jìn)行實(shí)驗(yàn)。

04.Hutool  BeanUtil

hutool是個(gè)人平常使用比較頻繁的一個(gè)工具包,對(duì)文件、加密解密、轉(zhuǎn)碼、正則、線程、XML等JDK方法進(jìn)行封裝,并且也可以進(jìn)行對(duì)象的拷貝。在使用前引入坐標(biāo): 

  1. <dependency>  
  2.     <groupId>cn.hutool</groupId>  
  3.     <artifactId>hutool-all</artifactId>  
  4.     <version>5.1.0</version>  
  5. </dependency> 

使用方法如下,并且使用的也是淺拷貝方式: 

  1. BeanUtil.copyProperties(orderPO,orderDTO); 

和Spring BeanUtils相同,也可以進(jìn)行屬性的忽略: 

  1. void copyProperties(Object source, Object target, String... ignoreProperties); 

除此之外,hutool的BeanUtil還提供了很多其他實(shí)用的方法:

個(gè)人在使用中感覺(jué)Bean和Map的互相轉(zhuǎn)換還是很常用的,有時(shí)在使用Map接收參數(shù)時(shí),后期能夠很方便的把Map轉(zhuǎn)換為Bean

05.Mapstruct

Mapstruct的使用和上面幾種方式有些不同,因?yàn)樯厦娴膸追N方式,spring和apache,hutool使用的都是反射,cglib是基于字節(jié)碼文件的操作,都是在都代碼運(yùn)行期間動(dòng)態(tài)執(zhí)行的,但是Mapstruct不同,它在編譯期間就生成了 Bean屬性復(fù)制的代碼,運(yùn)行期間就無(wú)需使用反射或者字節(jié)碼技術(shù),所以具有很高的性能。

使用Mapstruct需要需要引入下面的依賴: 

  1. <dependency>  
  2.     <groupId>org.mapstruct</groupId>  
  3.     <artifactId>mapstruct-jdk8</artifactId>  
  4.     <version>1.3.0.Final</version>  
  5. </dependency>  
  6. <dependency> 
  7.     <groupId>org.mapstruct</groupId>  
  8.     <artifactId>mapstruct-processor</artifactId> 
  9.     <version>1.3.0.Final</version>  
  10. </dependency> 

需要額外寫一個(gè)接口來(lái)實(shí)現(xiàn): 

  1. @Mapper  
  2. public interface ConvertMapper {  
  3.     OrderDTO po2Dto(OrderPO orderPO);  

這里的@Mapper注解不是用于mybatis的注解,而是org.mapstruct.Mapper。使用起來(lái)也非常簡(jiǎn)單: 

  1. ConvertMapper mapper = Mappers.getMapper(ConvertMapper.class);  
  2. OrderDTO orderDTO=mapper.po2Dto(orderPO); 

查看編譯后的target目錄,編譯時(shí)將我們定義的ConvertMapper 接口,生成了ConvertMapperImpl實(shí)現(xiàn)類,并實(shí)現(xiàn)了po2Dto方法??匆幌戮幾g生成的文件:

可以看到方法中為每一個(gè)屬性生成了set方法,并且對(duì)于引用對(duì)象,生成了一個(gè)新的對(duì)象,使用深拷貝的方式,所以修改之前的引用對(duì)象,這里的值也不會(huì)改變。并且,這種使用set/get的方式比使用反射的速度更快。

06.Dozer

Dozer是一個(gè)Bean到Bean映射器,它以遞歸方式將數(shù)據(jù)從一個(gè)對(duì)象復(fù)制到另一個(gè)對(duì)象,并且這些Bean可以具有不同的復(fù)雜類型。使用前引入依賴坐標(biāo): 

  1. <dependency>  
  2.   <groupId>net.sf.dozer</groupId>  
  3.   <artifactId>dozer</artifactId>  
  4.   <version>5.4.0</version>  
  5. </dependency> 

調(diào)用方式非常簡(jiǎn)單: 

  1. DozerBeanMapper mapper = new DozerBeanMapper();  
  2. OrderDTO orderDTO=mapper.map(orderPO,OrderDTO.class); 

查看運(yùn)行時(shí)生成的對(duì)象,可以看見(jiàn)使用的深拷貝的方式:

除此之外,還可以配置不同屬性名稱的映射,修改DTO和PO,在PO中添加一個(gè)name屬性,在DTO中添加value屬性: 

  1. @Data  
  2. public class OrderPO {  
  3.     Integer id;  
  4.     String orderNumber;  
  5.     List<String> proId;  
  6.     String name;  
  7.  
  8. @Data  
  9. public class OrderDTO {  
  10.     int id;  
  11.     String orderNumber;  
  12.     List<String> proId;  
  13.     String value;  

新建一個(gè)配置文件,在mapping中可以添加字段的映射關(guān)系: 

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.           xsi:schemaLocation="http://dozer.sourceforge.net  
  4.           http://dozer.sourceforge.net/schema/beanmapping.xsd">  
  5.     <mapping>  
  6.         <class-a>com.cn.entity.OrderPO</class-a>  
  7.         <class-b>com.cn.entity.OrderDTO</class-b> 
  8.          <field>  
  9.             <a>name</a>  
  10.             <b>value</b>  
  11.         </field>  
  12.     </mapping>  
  13. </mappings> 

DozerBeanMapper使用上面的配置文件進(jìn)行配置,再次拷貝對(duì)象: 

  1. ...  
  2. orderPO.setName("hydra");  
  3. DozerBeanMapper mapper = new DozerBeanMapper();  
  4. List<String> mappingFiles = new ArrayList<>();  
  5. mappingFiles.add("dozer.xml");  
  6. mapper.setMappingFiles(mappingFiles);  
  7. OrderDTO orderDTO=mapper.map(orderPO,OrderDTO.class); 

查看測(cè)試結(jié)果,不同名稱的字段也可以進(jìn)行拷貝了: 

  1. OrderPO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2], name=hydra 
  2. OrderDTO(id=1orderNumberorderNumber=orderNumber, proId=[1, 2], value=hydra

如果業(yè)務(wù)場(chǎng)景中的Bean具有很多不同的屬性,這么配置起來(lái)還是很麻煩的,需要額外手寫很多xml文件。以上就是工作中常被接觸到的幾種對(duì)象拷貝工具,在具體的使用中,更多的要結(jié)合拷貝效率等要求,以及工作場(chǎng)景中需要使用的是深拷貝還是淺拷貝等諸多因素。 

 

責(zé)任編輯:龐桂玉 來(lái)源: Java知音
相關(guān)推薦

2018-09-04 10:24:35

網(wǎng)絡(luò)流量提取工具

2010-09-29 10:01:57

2016-08-30 11:48:10

大數(shù)據(jù)術(shù)語(yǔ)

2009-07-23 16:14:03

.NET測(cè)試工具NUnit2.5

2019-04-25 16:03:00

深度學(xué)習(xí)編程人工智能

2025-06-17 08:25:00

Kubernetes集群容器

2017-06-26 10:35:58

前端JavaScript繼承方式

2019-08-02 08:50:47

API架構(gòu)微服務(wù)

2009-08-18 17:53:08

思科認(rèn)證介紹思科培訓(xùn)

2009-07-27 14:19:01

Eclipse JDT

2021-07-29 09:00:00

Python工具機(jī)器學(xué)習(xí)

2011-05-11 10:00:57

2019-12-03 12:16:36

物聯(lián)網(wǎng)ZigBee藍(lán)牙低功耗

2023-11-28 15:32:30

負(fù)載均衡算法

2024-11-20 15:24:49

2019-01-17 10:58:52

JS異步編程前端

2010-11-15 09:55:35

Oracle轉(zhuǎn)換函數(shù)

2011-01-11 09:53:28

linux進(jìn)程

2011-01-11 10:06:14

linux進(jìn)程

2021-06-08 09:47:44

Java面向對(duì)象
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)