1. 程式人生 > 實用技巧 >【Java】Bean複製幾種實現方法效能比較

【Java】Bean複製幾種實現方法效能比較

【引言】

在專案開發過程中,會遇到將某個已有若干屬性值的Bean複製給另一個具有相同屬性名的Bean,除了一個一個屬性去set方法之外,其實可以通過呼叫一些工具類下的方法直接copy,這樣就避免了一個一個去set屬性值,在簡化了程式碼的基礎上,也能快速地實現功能。

而實現這種功能的工具類並不只有一種,也聽同事提到過如果資料量大的話,效能上會有影響。所以在工作空閒之時,自己寫了個介面,測試了一下每種方法需要花費的時間,寫個部落格記錄下來。

【方法】

Apache 的BeanUtils
Apache 的PropertyUtils
Spring 的BeanUtils
反射工具包ReflectASM 自定義工具類

【測試】

測試的場景是在我們的商品應用服務中,寫了一個介面,查詢商品資料比較多的一個店鋪,大概8萬條左右,將查出來的實體ShopGoods資料拷貝到一個數據傳輸實體ShopGoodsDTO,結果返回的是拷貝所花費的時間,單位為毫秒。

下面是測試結果統計:

實現方法 花費時間(ms)

Apache 的BeanUtils    9431
Apache 的PropertyUtils    8083
Spring 的BeanUtils    4827
反射工具包ReflectASM 自定義工具類    4777


【程式碼】

//利用反射工具包ReflectASM自定義工具類
public class
BeanUtils { private static Map<Class, MethodAccess> methodMap = new HashMap<Class, MethodAccess>(); private static Map<String, Integer> methodIndexMap = new HashMap<String, Integer>(); private static Map<Class, List<String>> fieldMap = new HashMap<Class, List<String>>();
public static void copyProperties(Object desc, Object orgi) { MethodAccess descMethodAccess = methodMap.get(desc.getClass()); if (descMethodAccess == null) { descMethodAccess = cache(desc); } MethodAccess orgiMethodAccess = methodMap.get(orgi.getClass()); if (orgiMethodAccess == null) { orgiMethodAccess = cache(orgi); } List<String> fieldList = fieldMap.get(orgi.getClass()); for (String field : fieldList) { String getKey = orgi.getClass().getName() + "." + "get" + field; String setkey = desc.getClass().getName() + "." + "set" + field; Integer setIndex = methodIndexMap.get(setkey); if (setIndex != null) { int getIndex = methodIndexMap.get(getKey); // 引數一需要反射的物件 // 引數二class.getDeclaredMethods 對應方法的index // 引數對三象集合 descMethodAccess.invoke(desc, setIndex.intValue(), orgiMethodAccess.invoke(orgi, getIndex)); } } } // 單例模式 private static MethodAccess cache(Object orgi) { synchronized (orgi.getClass()) { MethodAccess methodAccess = MethodAccess.get(orgi.getClass()); Field[] fields = orgi.getClass().getDeclaredFields(); List<String> fieldList = new ArrayList<String>(fields.length); for (Field field : fields) { if (Modifier.isPrivate(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) { // 是否是私有的,是否是靜態的 // 非公共私有變數 String fieldName = StringUtils.capitalize(field.getName()); // 獲取屬性名稱 int getIndex = methodAccess.getIndex("get" + fieldName); // 獲取get方法的下標 int setIndex = methodAccess.getIndex("set" + fieldName); // 獲取set方法的下標 methodIndexMap.put(orgi.getClass().getName() + "." + "get" + fieldName, getIndex); // 將類名get方法名,方法下標註冊到map中 methodIndexMap.put(orgi.getClass().getName() + "." + "set" + fieldName, setIndex); // 將類名set方法名,方法下標註冊到map中 fieldList.add(fieldName); // 將屬性名稱放入集合裡 } } fieldMap.put(orgi.getClass(), fieldList); // 將類名,屬性名稱註冊到map中 methodMap.put(orgi.getClass(), methodAccess); return methodAccess; } } }

/**
* 測試方法:將查出的商品實體資料利用不同工具包下的方法拷貝至一個新的傳輸實體
* 商品資料量:八萬左右
*/
public long costSeconds() {
List<ShopGoodsDTO> shopGoodsDTOList=new ArrayList<>();
ShopGoodsExample shopGoodsExample = new ShopGoodsExample();
shopGoodsExample.createCriteria().andStoreIdEqualTo(743);
// 查詢到的商品資料
List<ShopGoods> shopGoodsList = shopGoodsMapper.selectByExample(shopGoodsExample);
long costSeconds=0L;
if(shopGoodsList!=null && shopGoodsList.size()>0){
long startTime=System.currentTimeMillis();
for (ShopGoods shopGoods:shopGoodsList) {
ShopGoodsDTO shopGoodsDTO = new ShopGoodsDTO();
BeanUtils.copyProperties(shopGoodsDTO,shopGoods);
//org.springframework.beans.BeanUtils.copyProperties(shopGoods,shopGoodsDTO);
//BeanUtils.copyProperties(shopGoodsDTO,shopGoods);
// try {
// PropertyUtils.copyProperties(shopGoodsDTO,shopGoods);
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// }
System.out.println(new Gson().toJson(shopGoodsDTO));
shopGoodsDTOList.add(shopGoodsDTO);
}
long endTime=System.currentTimeMillis();
costSeconds=endTime-startTime;
}
return costSeconds;
}


【總結】

通過以上測試可以看出,Apache下的工具包下的方法效能較差,和Spring工具包下的方法及利用反射工具包ReflectASM自定義工具類的方法相比,時間上是需要多花一倍的。

而Spring工具包下的方法與利用反射工具包ReflectASM自定義工具類的方法相比,時間上是差不多的。

所以個人感覺,我們需要實現此類功能的時候,直接利用Spring BeanUtils工具包下的copyProperties方法即可。需要注意的是Spring BeanUtils下的方法引數與Apache BeanUtils下的方法引數是相反的,在使用時不要將源實體與目標實體弄混了。
————————————————
版權宣告:本文為CSDN博主「好好生活_」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/u013034223/java/article/details/88063629