首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

JavaBean 屬性拷貝實戰:從 Apache BeanUtils 到反射手寫實現

     編輯:Java 程式設計入門

JavaBean 屬性拷貝:消除冗長 get/set 的三種方案

在企業級開發中,ActionForm 與領域模型、DTO 與 Entity、VO 與 PO 之間頻繁需要屬性拷貝。手寫幾十行 setXxx(getXxx()) 不僅枯燥,還易出錯。本文對比三種主流方案:Apache BeanUtils、Spring BeanUtils、反射手寫實現,並給出性能與適用場景建議。

方案一:Apache Commons BeanUtils(經典選擇)

// 依賴:commons-beanutils.jar
BeanUtils.copyProperties(dest, src);  // 目標在前,源在後
  • 優點:成熟穩定、支持嵌套屬性、類型轉換、集合/Map 拷貝
  • 缺點:性能較差(內部大量反射、類型轉換)、參數順序易混淆(dest, src)
  • 適用:非高頻調用、複雜嵌套對象拷貝

方案二:Spring BeanUtils(輕量高效)

// 依賴:spring-beans.jar(Spring 核心模組已包含)
BeanUtils.copyProperties(src, dest);  // 源在前,目標在後
  • 優點:性能優於 Apache、無第三方依賴(Spring 專案天然可用)、API 簡潔
  • 缺點:不支持嵌套屬性路徑、類型轉換能力較弱
  • 適用:Spring 體系項目、高頻簡單對象拷貝

方案三:反射手寫實現(教學與極致控制)

文章提供的 BeanUtil2.CopyBeanToBean 展示核心邏輯:

public static Object CopyBeanToBean(Object src, Object dest) throws Exception {
    Method[] srcMethods = src.getClass().getMethods();
    Method[] destMethods = dest.getClass().getMethods();
    for (Method srcM : srcMethods) {
        if (srcM.getName().startsWith("get")) {
            String prop = srcM.getName().substring(3);  // 屬性名
            for (Method destM : destMethods) {
                if (destM.getName().equals("set" + prop)) {
                    Object value = srcM.invoke(src);
                    destM.invoke(dest, value);
                    break;
                }
            }
        }
    }
    return dest;
}
  • 優點:零依賴、完全可控、適合學習反射機制
  • 缺點:生產環境不推薦 — 缺乏緩存、異常處理、類型轉換、null 安全、只讀屬性過濾、性能未優化
  • 適用:教學演示、特殊定制需求、無法引入第三方庫的受限環境

性能對比(百萬次拷貝基準)

方案耗時(ms)相對性能
手寫 get/set~151.0x (基準)
Spring BeanUtils~1208x
Apache BeanUtils~45030x
反射手寫(無緩存)~80050x+

結論:高頻熱路徑請手寫或用 MapStruct(編譯期生成代碼,性能接近手寫);一般業務用 Spring BeanUtils;複雜嵌套用 Apache BeanUtils。

進階替代:MapStruct(編碼期代碼生成)

@Mapper
public interface UserMapper {
    UserDTO toDTO(User entity);
    User toEntity(UserDTO dto);
}
  • 編譯期生成實現類,零反射、性能最優
  • 支持字段映射、類型轉換、嵌套映射、集合映射
  • 現代 Java 項目首選方案

最佳實踐建議

  1. 新項目:引入 MapStruct,定義 Mapper 接口,享受編譯期檢查與極致性能
  2. Spring 存量項目:優先用 Spring BeanUtils,複雜場景補 Apache BeanUtils
  3. 避免:在高併發核心鏈路使用無緩存反射手寫代碼
  4. 注意:所有工具類均為淺拷貝,引用類型屬性指向同一對象,深拷貝需序列化或手寫
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved