天天看點

BeanCopier性能對比

概述

常見或常用的幾種Bean屬性複制工具

  • Apache.BeanUtils
  • Apache.PropertyUtil
  • Spring.BeanUtils
  • Cglib.BeanCopier
  • MapStruct
  • EZMorph

使用場景:Dto與Entity轉換

  • 普通屬性複制
  • 個别屬性過濾
  • 屬性類型轉換
  • 數組或集合拷貝

性能對比

測試在兩個簡單的Bean之間轉換的耗時,執行次數分别為10、100、1k、10k、100k,時間機關為ms。

BeanCopier性能對比

源碼分析

Apache.BeanUtils

org.apache.commons.beanutils
  1. 通過内省(Introspector)擷取源類型的屬性資訊
  2. 判斷源類型的屬性是否可讀及目标類型的屬性是否可寫
    • 可讀
      • 有getter方法
    • 可寫
      • 有setter方法
  3. 進行複制
    1. 擷取屬性名
    2. 擷取屬性類型
    3. 進行屬性值轉類型[自帶類型轉換器,提供注冊自定義轉換器接口]
    4. 指派
      BeanCopier性能對比

執行過程

  1. 擷取工具執行個體,調用屬性複制方法
    BeanCopier性能對比
  2. 擷取執行個體方法
    BeanCopier性能對比
  3. 執行個體擷取的函數是同步的,因為ContextClassLoader的不同,每個線程都會建立一個執行個體
    BeanCopier性能對比
  4. 屬性複制函數:先是空值的判斷,然後通過Java内省機制擷取屬性描述,判斷屬性是否可讀/可寫,然後通過反射指派
    BeanCopier性能對比

發現在初始化過程中,BeanUtils執行個體的擷取是“假單例”模式,每個線程擁有一個BeanUtils執行個體,是以每個線程每次初始化都消耗資源。

Apache.PropertyUtils

org.apache.comons.beanutils

使用内省,操作getter/setter方法。基本流程同Apache.BeanUtils

差別

BeanUtils支援屬性類型轉換,而PropertyUtils不支援,若有同名不同類型的屬性,則會報錯。

BeanCopier性能對比

BeanUtils自帶類型轉換器,支援如下類型轉換:

  • java.lang.BigDecimal
  • java.lang.BigInteger
  • boolean and java.lang.Boolean
  • byte and java.lang.Byte
  • char and java.lang.Character
  • java.lang.Class
  • double and java.lang.Double
  • float and java.lang.Float
  • int and java.lang.Integer
  • long and java.lang.Long
  • short and java.lang.Short
  • java.lang.String
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

Springframework.beans.BeanUtils

org.springframework.beans.BeanUtils

Spring的BeanUtils也是通過java内省機制擷取getter/setter,然後通過反射調用進而實作屬性複制,但差別于Apache的BeanUtils,Spring的BeanUtils為單例模式,不需要重複建立。同時,Spring.BeanUtils支援忽略屬性。

Cglib BeanCopier

net.sf.cglib.beans

使用動态代理,生成位元組碼類,再通過Java反射成Class,調用其copy方法。

執行過程

  • 建立BeanCopier
    BeanCopier性能對比
    BeanCopier性能對比
    [使用了緩存,該過程也消耗資源,建議全局隻初始化一次]
    BeanCopier性能對比
    BeanCopier性能對比
    通過位元組碼生成了兩個類
    • KeyFactory
    • BeanCopier
  • 調用copy方法。
    BeanCopier性能對比

    (支援自定義類型轉換器)

    【有convert的情況】

    BeanCopier性能對比
    【無convert的情況】
    BeanCopier性能對比
    生成的BeanCopier裡面直接使用Bean的setter/getter

MapStruct

org.mapstrcut.*

http://mapstruct.org/

支援XML配置和注解配置

使用示例

  • 自定義Mapper類
BeanCopier性能對比
  • 編譯生成實作類
BeanCopier性能對比
  • Bean複制
BeanCopier性能對比

EZMorph

性能感人,不做深究。

也是通過反射

功能次元對比

根據屬性複制工具的功能次元對工具進行分析,對比如下:

  • Apache.BeanUtils
    BeanCopier性能對比
  • Apache.PropertyUtil
    BeanCopier性能對比
  • Spring.BeanUtils
    BeanCopier性能對比
  • Cglib.BeanCopier
    BeanCopier性能對比
  • MapStruct
    BeanCopier性能對比
  • EZMorph
    BeanCopier性能對比

總結

根據不同工具的性能及功能次元,個人建議當對象轉換操作較少或者應用對性能要求較高時,盡量不采用工具,而是手寫getter/setter;在不考慮性能的情況下,普通的對象轉換可以使用Cglib.BeanCopier,複雜的對象轉換使用MapStruct。