精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

為什么不推薦使用 BeanUtils.copyProperties?

開發
本文通過分析BeanUtils.copyProperties的源碼,總結了它的幾個缺點,綜合評估,建議慎用!

在日常開發中,經常涉及到 VO、DTO、DO等對象之間的屬性拷貝,為了避免使用原始的setter和getter方法,我們通常過借助一些三方工具,本文我們將聊聊某程序員使用BeanUtils.copyProperties工具,導致差點被開除的血淚史。

一、BeanUtils.copyProperties是什么?

BeanUtils.copyProperties是一個對象拷貝的常用工具,Spring和Apache都提供了對應的靜態方法,兩者源碼如下:

// org.springframework.beans.BeanUtils
public static void copyProperties(Object source, Object target) throws BeansException {
    copyProperties(source, target, null, (String[]) null);
}

// org.apache.commons.beanutils.BeanUtils
public static void copyProperties(final Object dest, final Object orig)
        throws IllegalAccessException, InvocationTargetException {
    BeanUtilsBean.getInstance().copyProperties(dest, orig);
}

通過上述兩個源碼方法可以發現:兩個方法中的入參源對象和目標對象 順序是反的,所以在使用時,一定要注意具體導入的是哪一個BeanUtils,切勿把入參順序搞反。

接著,分別解析兩種方式的源碼實現原理:

1.Spring實現

org.springframework.beans.BeanUtils的源碼實現如下圖:

整個源碼的實現邏輯總結成下面 7個步驟:

  1. Spring的 BeanUtils拷貝,使用的是反射機制
  2. 先獲取target中所有字段以及它們的getter和setter方法
  3. 遍歷target的字段,如果字段有setter方法或者不是忽略對象則進行下一步操作,否則忽略
  4. 用target的字段去source中獲取對應的值(通過getter方法),有值則進行下一步,否則忽略
  5. 獲source和target中同一個字段的類型,并且判斷類型是否相同,相同則繼續下一步,否則忽略
  6. 如果source和target的字段是非public,則通過反射修改權限
  7. 最后,通過反射完成賦值
  8. 通過源碼分析,我們能夠看出org.springframework.beans.BeanUtils的拷貝屏蔽了很多的異常,總結如下:
  • source和target的字段缺少getter和setter方法,拷貝失敗
  • source和target的字段名稱不同,拷貝失敗,即字段名相同才可以拷貝
  • source和target的字段類型不同,拷貝失敗,即類型相同才可以拷貝
  • 對于Map類型,無法拷貝

對于上述前 3種拷貝失敗的場景,編譯期間無法感知,一旦代碼上線大概率會出 bug,另外,因為使用的反射機制,性能略有影響。

2.Apache實現

org.apache.commons.beanutils.BeanUtils的源碼實現如下圖:

通過源碼我們能夠看出:Apache的實現其實是對Spring的一種增強,增加了DynaBean和Map兩種類型的拷貝,它們的實現都是采用反射機制。

另外,Spring和 Apache的兩種實現方案都是淺拷貝,也就是說,如果對象中還有內嵌對象,如果不做額外處理,拷貝會失敗。

所謂淺拷貝,淺拷貝是一種復制對象的方式,它創建一個新對象,這個新對象是原對象的副本,但對于對象中引用類型的字段,淺拷貝只復制它們的引用,而不復制它們所指向的實際對象。換句話說,淺拷貝只拷貝對象的第一層屬性,對于屬性中的引用類型,只拷貝引用地址。

如下示例,當source內部Inner對象的 address字段更改了,target的也跟著變更了:

二、為什么不推薦BeanUtils.copyProperties

在上面源碼分析的過程中可以發現:只有同時滿足下面 3個條件才能拷貝成功:

  • source和target的字段需要有getter和setter方法
  • source和target的字段名稱需要相同
  • source和target的字段類型需要相同

以上 3個條件缺失任何一個拷貝都會失敗,但是編譯器無法感知,對程序員不友好。

假如,在開發中忘記寫getter和setter,使用BeanUtils.copyProperties拷貝不會有異常,但是業務邏輯上沒有達到預期,所以這種異常要么在測試中發現,要么需要跑真實的業務邏輯才能發現。

還有一種場景,假如source中有個money字段一開始被程序員A定義成double類型,后面被程序員B 修改成了BigDecimal,程序員B發現代碼沒有報錯,而且是一個小修改就直接上線了。

1天后,有人反饋線上出問題了,經過好一番努力地排查發現,使用BeanUtils.copyProperties拷貝,source中的money字段是BigDecimal類型,而target的money字段是double類型,最終導致拷貝失敗,而這位差點被開除的程序員恰好是這種場景。

基于上述描述,BeanUtils.copyProperties無法在編譯期間對拷貝字段的修改及時感知錯誤,假如公司上線規范不嚴,或者回歸測試不全面,一旦出現上述字段名稱或者類型被修改,很大可能造成線上問題,所以需要慎用BeanUtils.copyProperties。

三、替代方案

既然BeanUtils.copyProperties拷貝存在上述問題,那么,有沒有什么好的替代方案呢?

有,通常替代方案有 2種:使用原始的setter和getter方法 和 MapStruct。

1.原始的setter和getter

使用原始的setter和getter方法進行拷貝,雖然會編寫一些看似啰嗦的代碼,但是它具備以下優點:

  • 控制的粒度更細,更靈活
  • 性能比BeanUtils.copyProperties的反射更高效
  • 如果拷貝字段有名稱和類型更改或者setter和getter方法丟失,編譯期立馬能發現
  • 如下示例,可以將多個Source的字段按需拷貝到Target上:
import java.util.UUID;

public Target convetSourceToTarget(Source1 source1, Source2 source2) {
    Target target = new Target();
    target.setId(UUID.randomUUID().toString());
    target.setName(source1.getName());
    target.setAge(source1.getAge());
    target.setAddress(source2.getAddress());
}

2.MapStruct

(1) 使用示例

MapStruct是一個很優秀的 Java庫,也是用于簡化對象之間的拷貝工作,其主要特點如下:

  • 編譯時生成代碼:MapStruct在編譯時生成映射代碼,避免了運行時的性能開銷
  • 類型安全:生成的代碼是類型安全的,編譯時即可發現映射錯誤
  • 易于使用:通過注解配置,使用簡單直觀

為了更好地說明 MapStruct,我們以一個示例進行說明:

首先,我們需要增加mapstruct的依賴:

// maven 依賴
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.2.Final</version>
</dependency>
// gradle依賴
implementation 'org.mapstruct:mapstruct:1.5.2.Final'

然后,定義一個Mapper接口:

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface TestMapper {
    TestMapper INSTANCE = Mappers.getMapper(TestMapper.class);
    /**
     * 在Mapping中定義對象的 source和 target字段,
     * 如果source和 target的類型不一樣,編譯期會報錯
    */
    @Mapping(source = "name", target = "fullName") 
    UserDTO toDTO(UserEntity entity);
}

接著,定義兩個實體類:

public class UserDTO {
    private String fullName;
    private int age;
}

public class UserEntity {
    private String name;
    private int age;
}

最后,寫一個測試類:

public class MapStructTest {
    public static void main(String[] args) {
        UserEntity entity = new UserEntity();
        entity.setName("John");
        entity.setAge(30);

        UserDTO dto = TestMapper.INSTANCE.toDTO(entity);
        System.out.println(dto.getFullName()); // 輸出: John
        System.out.println(dto.getAge());  // 輸出: 30
    }
}

上述代碼,在編譯器會自動創建一個TestMapperImpl實現類,如下圖:

(2) 實現原理

最后,總結下MapStruct實現原理:

① 注解處理器機制

MapStruct使用了 Java的注解處理器機制,通過實現javax.annotation.processing.Processor接口,在編譯時掃描和處理特定的注解。

② 注解掃描與處理

MapStruct定義了@Mapper、@Mapping 等注解,編譯器會調用注解處理器來處理這些注解。

③ 代碼生成

MapStruct會根據注解信息,解析源類和目標類的結構,并生成相應的映射,大致有以下幾個步驟:

  • 解析注解和類結構:MapStruct 解析@Mapper接口、方法簽名以及@Mapping注解,獲取源類和目標類的字段信息。
  • 生成映射方法:根據解析結果,生成具體的映射方法,并調用源類的getter方法獲取值并賦值給目標類的對應字段。
  • 處理復雜映射:對于嵌套對象、集合等復雜結構,MapStruct會遞歸生成相應的映射代碼

④ 類型安全與錯誤檢查

在代碼生成過程中,MapStruct會進行類型檢查,確保源字段和目標字段的類型匹配,如果發現類型不匹配會報編譯時錯誤。

⑤ 支持自定義

MapStruct允許用戶自定義映射邏輯,比如下面的示例,通過qualifiedByName和 @Named注解實現了一個自定義的方法:

@Mapping(target = "tags", source = "tagSet", qualifiedByName = "defaultToEmptySet")
UserEntity fromDO(UserDTO dto);

@Named("defaultToEmptySet")
default Set<String> defaultToEmptySet(Set<String> items) {
    return items == null ? new LinkedHashSet<>() : items;
}

四、如何選擇?

原始的setter和getter方法簡單且靈活,mapstruct通過注解的方式,比起原始的setter和getter門檻會高一點。

兩種方式都是編譯行為,因此,一旦拷貝的字段發生改變能及時感知,對程序員比較友好。

具體如何選擇,可以根據團隊約定而定,如果是個人學習,優先推薦mapstruct,可以作為一個學習和實踐點。

五、總結

本文通過分析BeanUtils.copyProperties的源碼,總結了它的幾個缺點,綜合評估,建議慎用!

接著,通過分析mapstruct的原理以及使用案例,它完美解決了BeanUtils.copyProperties的缺點,是對象拷貝很不錯的選擇。

對于原始的setter和getter也是對象拷貝很不錯的選擇。

溫馨建議:如果使用三方的工具類,一定要事先了解其優缺點和安全性問題,這樣才能在使用過程中能做到心中有譜,處事不亂,避免拆盲盒導致不必要的事故。如果有更多的精力,再去研究下其原理,吸收他人優秀的思維。

責任編輯:趙寧寧 來源: 猿java
相關推薦

2023-05-29 08:56:34

深拷貝淺拷貝對象

2024-02-27 10:42:04

開發代碼測試

2024-11-29 08:20:22

Autowired場景項目

2022-12-07 08:45:45

工具Springweb

2024-11-12 10:30:54

Docker部署數據庫

2022-12-09 07:53:20

vo2dto方法AOP

2025-05-16 02:00:00

HashMapJava代碼

2024-09-12 08:32:42

2023-11-06 13:04:59

Python日志庫

2021-08-23 13:02:50

MySQLJOIN數據庫

2025-10-17 01:25:00

SpringIDEA@Autowired

2022-01-11 10:29:32

Docker文件掛載

2025-04-29 07:06:20

2021-07-04 14:19:03

RabbitMQ消息轉換

2021-01-13 09:55:29

try-catch-fJava代碼

2018-11-29 14:30:42

數據庫外鍵約束應用程序

2020-08-31 11:20:53

MySQLuuidid

2024-03-11 11:02:03

Date類JavaAPI

2023-09-27 23:03:01

Java虛擬線程

2020-07-02 14:12:52

C++語言編程
點贊
收藏

51CTO技術棧公眾號

只有这里有精品| 国产精品视频999| 亚洲狠狠婷婷综合久久久久图片| 在线人成日本视频| 国产精品久久久久久久久免费桃花 | 日韩高清国产一区在线| 色yeye香蕉凹凸一区二区av| 97免费公开视频| 日韩中文影院| 亚洲影视在线播放| 视频在线99| 丰满熟妇乱又伦| 蜜臀av一区二区三区| 久久久久久久国产| 国产一区二区三区视频播放| 国产一区二区三区亚洲| 欧美日韩dvd在线观看| 国产人妻777人伦精品hd| 亚洲搞黄视频| 久久久久久久久一| 99久久无色码| 亚洲在线视频播放| 玖玖精品视频| 午夜精品免费视频| 欧美日韩精品在线观看视频| 青青草综合网| 亚洲欧美激情一区| xxxwww国产| 年轻的保姆91精品| 欧美视频一区二区三区| 精品少妇一区二区三区在线| 97超碰资源站在线观看| 国产精品入口麻豆原神| 欧洲久久久久久| 婷婷开心激情网| 国产成人亚洲综合a∨婷婷| 国产在线视频91| 中文字幕+乱码+中文| 午夜在线视频观看日韩17c| 欧美国产在线电影| 少妇aaaaa| 97欧美在线视频| 中文字幕亚洲一区二区三区五十路| 亚洲观看黄色网| 北条麻妃一区二区三区在线| 日韩欧美亚洲国产另类| 中文字幕日韩久久| 在线成人免费| 欧美老人xxxx18| 天天爽夜夜爽一区二区三区| 亚洲天堂1区| 欧洲色大大久久| 黄色一级免费大片| 国产一区二区三区影视| 欧美中文字幕一区| 亚洲精品视频导航| 国产精品天堂蜜av在线播放| 欧美日韩1区2区| 亚洲免费av一区| 一级欧美视频| 日韩欧美在线综合网| 亚洲天堂小视频| 黄色美女久久久| 日韩精品黄色网| 一级黄色片大全| 国产中文精品久高清在线不| 国产一区二区三区高清在线观看| 最新中文字幕av| 91麻豆国产自产在线观看亚洲| 中文字幕在线成人| 91香蕉一区二区三区在线观看| 91成人免费| 韩日欧美一区二区| 无码人妻黑人中文字幕| 日本中文字幕不卡| 成人美女av在线直播| 亚洲AV无码精品国产| gogo大胆日本视频一区| 欧美二区三区| 在线播放麻豆| 亚洲国产精品自拍| 国产二区视频在线播放| 国模私拍国内精品国内av| 7777精品伊人久久久大香线蕉完整版 | 91激情视频在线观看| 99精品美女| 久久琪琪电影院| 国产精品乱码一区二区视频| 韩国女主播成人在线| 国产精品乱码一区二区三区| 国产玉足榨精视频在线观看| 中文字幕欧美一区| 欧美日韩一道本| 四虎国产精品永久在线国在线| 欧美mv日韩mv国产网站app| av黄色免费网站| 亚洲欧美综合久久久| 97视频免费观看| 亚洲综合一区中| 99久久精品99国产精品| 亚洲一区二区三区四区中文| 国产探花视频在线观看| 欧美性色欧美a在线播放| 国产成人av免费观看| 精品视频亚洲| 久久久久久久成人| 中文字幕日本人妻久久久免费 | 国产高清一区视频| 国产51人人成人人人人爽色哟哟 | 99视频这里有精品| 亚洲色图色老头| 久草网在线观看| 麻豆freexxxx性91精品| 久久99国产精品| 最新超碰在线| 欧美三级电影网| 鲁大师私人影院在线观看| 香蕉国产精品| 国产精品普通话| 亚洲欧洲视频在线观看| 一区二区在线免费| 九九热精品在线播放| 婷婷综合电影| 欧美激情亚洲另类| 国产麻豆免费视频| 中文字幕一区二区三区在线不卡| av免费播放网址| 超碰精品在线观看| 免费av在线一区| 国产乱码久久久| 国产精品不卡在线观看| 91人人澡人人爽人人精品| 小说区图片区色综合区| 久久久久久中文| 国产福利第一页| 亚洲精品久久嫩草网站秘色| 免费成年人高清视频| japanese国产精品| 国产精品成人v| 大片免费播放在线视频| 色视频欧美一区二区三区| theav精尽人亡av| 久久aⅴ国产紧身牛仔裤| 精品一区二区三区自拍图片区| 美足av综合网| 亚洲白拍色综合图区| 久久这里只有精品国产| 成人黄色一级视频| 黄页免费在线观看视频| 国产美女撒尿一区二区| 久久久亚洲精品视频| 免费av网站观看| 天天av天天翘天天综合网| av黄色一级片| 国产精品视频| 日韩av在线一区二区三区| 成人午夜一级| 另类专区欧美制服同性| 性生活视频软件| 婷婷丁香激情综合| 久久无码人妻精品一区二区三区| 久久精品系列| 亚洲三级一区| 日韩在线亚洲| 91成人福利在线| 国产天堂在线| 7777精品伊人久久久大香线蕉的| 91视频综合网| 丁香五精品蜜臀久久久久99网站| 丰满少妇被猛烈进入高清播放| 香蕉久久夜色精品国产使用方法| 国产精品h在线观看| 亚洲欧美视频一区二区| 日韩一区二区在线看片| 日韩精品无码一区二区| 国产人成一区二区三区影院| 精品亚洲视频在线| 精品av久久久久电影| 欧美婷婷久久| 粉嫩av国产一区二区三区| 高清一区二区三区日本久| 你懂的视频在线| 欧美日韩美女一区二区| www.av视频| 99精品久久免费看蜜臀剧情介绍| 亚洲 中文字幕 日韩 无码| 亚洲91精品| 久久人人九九| 韩国一区二区三区视频| 欧美一二三视频| 国产三区视频在线观看| 亚洲免费电影在线观看| 国产色在线视频| 色综合视频一区二区三区高清| 久久久久久久麻豆| 91碰在线视频| 爱情岛论坛亚洲自拍| 老司机一区二区三区| 日本一区二区三区四区五区六区| 欧美**字幕| 成人免费视频视频在| 深夜视频一区二区| 97视频免费看| 91精品久久久久久粉嫩| 国产午夜精品视频| 丰满肉肉bbwwbbww| 69久久99精品久久久久婷婷| 日韩在线 中文字幕| 夜夜揉揉日日人人青青一国产精品| 熟女俱乐部一区二区| 国产传媒日韩欧美成人| 国产小视频精品| 一本一本久久| 人人妻人人澡人人爽欧美一区双| 日韩一区欧美| 欧美日韩亚洲免费| 麻豆一区一区三区四区| 51国偷自产一区二区三区的来源| 色天使综合视频| 国产+成+人+亚洲欧洲| a毛片在线观看| 久久精品视频在线| 在线视频91p| 亚洲女人初尝黑人巨大| 天堂在线视频免费观看| 欧美大胆一级视频| 国产成人麻豆精品午夜在线| 911精品国产一区二区在线| 波多野结衣一区二区三区四区| 欧美日韩国产中字| 国产乡下妇女做爰毛片| 一区二区三区在线免费播放| 欧美xxxooo| 中文字幕在线不卡国产视频| 国产一区二区三区四区在线| 国产无人区一区二区三区| www.超碰97| 久久嫩草精品久久久精品| 国产又粗又长又爽| 99精品欧美一区二区三区小说| 99精品一区二区三区无码吞精 | 欧美美女黄视频| 在线观看av大片| 欧美日韩一区不卡| 伊人22222| 欧美精品tushy高清| 91麻豆成人精品国产免费网站| 欧美日韩成人在线一区| 国产精品高潮呻吟久久久| 欧美久久免费观看| 99国产揄拍国产精品| 欧美一三区三区四区免费在线看 | 在线观看污污网站| 一本高清dvd不卡在线观看 | 日韩一区二区三区免费观看| 国产日韩一级片| 日韩欧美黄色影院| 日本黄色大片视频| 亚洲欧美日韩中文在线制服| 黄色av网址在线免费观看| 中文字幕av一区中文字幕天堂| 免费a级在线播放| 久热精品视频在线| 波多野结衣在线播放| 91av国产在线| 天天综合网站| 91麻豆国产精品| 最新国产精品精品视频| 国外成人免费视频| 国产精品手机在线播放| 自拍视频一区二区三区| 欧美日韩精品免费观看视频完整| 精品久久久久久久久久中文字幕| 麻豆成人在线| 午夜激情视频网| 97超碰欧美中文字幕| 中文天堂资源在线| 一区二区三区蜜桃| 久久久久久不卡| 欧美一区二区三区色| 香蕉av一区二区三区| 在线视频免费一区二区| 在线视频观看国产| 日本国产一区二区三区| www欧美在线观看| 精品蜜桃传媒| 色乱码一区二区三区网站| 欧美性猛交内射兽交老熟妇| 国产精品久久久久毛片大屁完整版| 免费黄色一级网站| 成人免费高清在线| 免费看黄色三级| 亚洲大尺度视频在线观看| 最近中文字幕在线观看| 精品国产制服丝袜高跟| 福利在线观看| 国外成人在线视频| 欧洲亚洲精品久久久久| 精品国产乱码一区二区三区四区| 99久久.com| 播放灌醉水嫩大学生国内精品| 精品亚洲国产成人av制服丝袜 | 国产精品三级视频| 国产污污视频在线观看| 欧美一区二区三区爱爱| 国产女人在线观看| 午夜精品久久久久久久男人的天堂 | 欧洲av一区二区三区| 亚洲综合色自拍一区| 一级片视频网站| 亚洲日本成人女熟在线观看| 欧洲精品二区| 91精品久久久久| 国产日产一区| 97超碰青青草| 成人高清在线视频| 2021亚洲天堂| 欧美狂野另类xxxxoooo| 黑人与亚洲人色ⅹvideos| 国外成人免费在线播放| 4438全国亚洲精品观看视频| 五月天综合婷婷| 精品一区二区三区久久| 日本一区二区视频在线播放| 一本久道中文字幕精品亚洲嫩| 你懂的网站在线| 欧美国产一区二区三区| 秋霞午夜一区二区三区视频| 国产精品无码乱伦| 蜜臀久久99精品久久久画质超高清| 亚洲天堂久久新| 狠狠久久亚洲欧美专区| 亚洲aaa在线观看| 97精品国产91久久久久久| 7777久久亚洲中文字幕| 亚洲二区在线| 国产美女无遮挡网站| 成人综合婷婷国产精品久久蜜臀| 色欲人妻综合网| 在线播放欧美女士性生活| 免费黄色网址在线观看| 国产精品视频男人的天堂| 欧美亚洲国产精品久久| 中文字幕第21页| 国产精品卡一卡二| 91久久精品国产91性色69| 日韩在线资源网| 青青草国产一区二区三区| 一区二区视频在线观看| 精品一区二区三区视频在线观看| 天天操夜夜操av| 欧美大片日本大片免费观看| 久草在线视频资源| 精品国产一区二区三区四区vr | 国产精品乱战久久久| 国产 日韩 欧美在线| 99r精品视频| 久久精品视频2| 日韩最新av在线| 麻豆视频久久| 很污的网站在线观看| 91在线视频播放地址| 无码视频一区二区三区| 日韩中文字幕不卡视频| 日本一区二区三区播放| 男人日女人视频网站| 久久亚洲私人国产精品va媚药| 亚洲第一网站在线观看| 日韩在线免费av| 91精品短视频| 成年人黄色片视频| 国产精品高潮呻吟久久| 亚洲AV无码精品自拍| 青青a在线精品免费观看| 日韩欧美综合| 性色av浪潮av| 色综合久久天天| 国产三区视频在线观看| 精品不卡在线| 久久精品国产99久久6| 一级aaa毛片| 国产一区二区三区毛片| 日韩视频1区| 国产精品-区区久久久狼| 亚洲欧洲av另类| 无码国产精品96久久久久| 国产精品久久久久77777| 亚洲欧美综合| 久久亚洲无码视频| 日韩精品一区二区三区四区视频| 2022成人影院| 亚洲国产一二三精品无码| 久久久久99精品一区| 国产黄色av网站| 国产99视频在线观看| 黄页网站一区| 欧美性猛交xxxx乱大交少妇| 亚洲精品www久久久| 国产精品1区在线| 日本美女高潮视频|