概述
常見或常用的幾種Bean屬性複制工具
- Apache.BeanUtils
- Apache.PropertyUtil
- Spring.BeanUtils
- Cglib.BeanCopier
- MapStruct
- EZMorph
使用場景:Dto與Entity轉換
- 普通屬性複制
- 個别屬性過濾
- 屬性類型轉換
- 數組或集合拷貝
性能對比
測試在兩個簡單的Bean之間轉換的耗時,執行次數分别為10、100、1k、10k、100k,時間機關為ms。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR5EeFpnTzcGVOpHOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmL5ETN1UTNwYTMzITNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
源碼分析
Apache.BeanUtils
org.apache.commons.beanutils
- 通過内省(Introspector)擷取源類型的屬性資訊
- 判斷源類型的屬性是否可讀及目标類型的屬性是否可寫
- 可讀
- 有getter方法
- 可寫
- 有setter方法
- 可讀
- 進行複制
- 擷取屬性名
- 擷取屬性類型
- 進行屬性值轉類型[自帶類型轉換器,提供注冊自定義轉換器接口]
- 指派
BeanCopier性能對比
執行過程
- 擷取工具執行個體,調用屬性複制方法
BeanCopier性能對比 - 擷取執行個體方法
BeanCopier性能對比 - 執行個體擷取的函數是同步的,因為ContextClassLoader的不同,每個線程都會建立一個執行個體
BeanCopier性能對比 - 屬性複制函數:先是空值的判斷,然後通過Java内省機制擷取屬性描述,判斷屬性是否可讀/可寫,然後通過反射指派
BeanCopier性能對比
發現在初始化過程中,BeanUtils執行個體的擷取是“假單例”模式,每個線程擁有一個BeanUtils執行個體,是以每個線程每次初始化都消耗資源。
Apache.PropertyUtils
org.apache.comons.beanutils
使用内省,操作getter/setter方法。基本流程同Apache.BeanUtils
差別
BeanUtils支援屬性類型轉換,而PropertyUtils不支援,若有同名不同類型的屬性,則會報錯。
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的情況】
【無convert的情況】BeanCopier性能對比 生成的BeanCopier裡面直接使用Bean的setter/getterBeanCopier性能對比
MapStruct
org.mapstrcut.*
http://mapstruct.org/
支援XML配置和注解配置
使用示例
- 自定義Mapper類
- 編譯生成實作類
- Bean複制
EZMorph
性能感人,不做深究。
也是通過反射
功能次元對比
根據屬性複制工具的功能次元對工具進行分析,對比如下:
- Apache.BeanUtils
BeanCopier性能對比 - Apache.PropertyUtil
BeanCopier性能對比 - Spring.BeanUtils
BeanCopier性能對比 - Cglib.BeanCopier
BeanCopier性能對比 - MapStruct
BeanCopier性能對比 - EZMorph
BeanCopier性能對比
總結
根據不同工具的性能及功能次元,個人建議當對象轉換操作較少或者應用對性能要求較高時,盡量不采用工具,而是手寫getter/setter;在不考慮性能的情況下,普通的對象轉換可以使用Cglib.BeanCopier,複雜的對象轉換使用MapStruct。