業務系統中經常需要兩個對象進行屬性的拷貝,不能否認逐個的對象拷貝是最快速最安全的做法,但是當數據對象的屬性字段數量超過程序員的容忍的程度比如通常超過5個屬性的時候,代碼因此變得臃腫不堪,使用一些方便的對象拷貝工具類將是很好的選擇。
目前流行的較為公用認可的工具類:
Apache的兩個版本:(反射機制)
org.apache.commons.beanutils.PropertyUtils.copyProperties(Object dest, Object orig)
org.apache.commons.beanutils.BeanUtils.copyProperties(Object dest, Object orig)
Spring版本:(反射機制)
org.springframework.beans.BeanUtils.copyProperties(Object source, Object target, Class editable, String[] ignoreProperties)
新版本的spring也集成了cglib版:org.springframework.cglib.beans.BeanCopier
cglib版本:(使用動態代理,效率高)
net.sf.cglib.beans.BeanCopier.copy(Object paramObject1, Object paramObject2, Converter paramConverter)
dozer版本(xml配置映射,性能最低下):
就API而言,使用哪個工具類無所謂,我們通常關心兩點,功能完善性以及性能。
性能測試:
// 源POJO package tf56.lf.lfbase.model.dto; import java.io.Serializable; import tf56.lf.lfbase.model.domain.LfProduct; /** * ClassName:ProductDTO * * @version 1.0 * @since v1.0 * @Date 2017年6月19日 yuebiao.wu */ public class ProductDTO extends LfProduct implements Serializable{ private static final long serialVersionUID = -1296801547926874402L; } // 目標POJO package tf56.lf.lfbase.model.domain; import java.io.Serializable; import java.util.Date; import lombok.Getter; import lombok.Setter; /** * ClassName:Product * * @author tool * @version 1.0 * @since v1.0 * Date Jun 26, 2017 2:40:42 PM */ @Getter @Setter public class LfProduct implements Serializable { private static final long serialVersionUID = 4054863309367744108L; /* 產品id */ private String lfProductId; /* 物流金融賬號 */ private String lfAccountId; /* 產品名稱 */ private String productName; /* 產品類型(BAOFU:保付; MIAOFU:秒付; JISHIFU:即時付;) */ private String productType; /* 適用場景列表(逗號分隔)(COD:代收貨款; FREIGHT:運費;) */ private String sceneTypes; /* 產品描述 */ private String productDescription; /* 產品規則描述 */ private String productRoleDescription; /* 放款觸發行為 */ private String loanAction; /* 收款觸發行為 */ private String repayAction; /* 產品狀態(ENABLE:啟用; DISABLE:停用;) */ private String productStatus; /* 預警閥值 */ private Long warnBalance; /* 發貨人是否控制額度(1:是; 0:否;) */ private Integer isConsignerCreditLimit; /* 承運商是否控制額度(1:是; 0:否;) */ private Integer isExpressCreditLimit; private String productAgreementUrl; private String poundageCalcType; private String poundageRate; /* 備注1 */ private String remark1; /* 操作員編號 */ private String operatorId; /* 輸入日期 */ private Date inputDate; /* 記錄更新時間 */ private Date stampDate; }
BeanCopier
Mapper wrapper = new DozerBeanMapper(); ProductDTO pdt = new ProductDTO(); pdt.setIsConsignerCreditLimit(3); pdt.setLoanAction("323f3"); pdt.setProductName("feiwefe"); pdt.setPoundageRate("f332r3"); long beg = System.currentTimeMillis(); PropertyUtilsBean bean = new PropertyUtilsBean(); BeanCopier copier = BeanCopier.create(ProductDTO.class, LfProduct.class, false); for (int i=0;i<1000;i++) { LfProduct lfPdt = new LfProduct(); // try { // try { // bean.copyProperties(lfPdt, pdt); // } catch (IllegalAccessException | InvocationTargetException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } catch (NoSuchMethodException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } copier.copy(pdt, lfPdt, null); if (i==3) { // System.out.println(JacksonHelper.toJSON(lfPdt)); } // lfPdt = wrapper.map(pdt, LfProduct.class); lfPdt.setInputDate(new Date()); } System.out.println(System.currentTimeMillis() - beg);
大約140ms左右。
Mapper wrapper = new DozerBeanMapper(); ProductDTO pdt = new ProductDTO(); pdt.setIsConsignerCreditLimit(3); pdt.setLoanAction("323f3"); pdt.setProductName("feiwefe"); pdt.setPoundageRate("f332r3"); long beg = System.currentTimeMillis(); PropertyUtilsBean bean = new PropertyUtilsBean(); BeanCopier copier = BeanCopier.create(ProductDTO.class, LfProduct.class, false); for (int i=0;i<1000;i++) { LfProduct lfPdt = null; // try { // try { // bean.copyProperties(lfPdt, pdt); // } catch (IllegalAccessException | InvocationTargetException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } catch (NoSuchMethodException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // copier.copy(pdt, lfPdt, null); if (i==3) { // System.out.println(JacksonHelper.toJSON(lfPdt)); } lfPdt = wrapper.map(pdt, LfProduct.class); lfPdt.setInputDate(new Date()); } System.out.println(System.currentTimeMillis() - beg);
2500ms。
PropertyUtilsBean
Mapper wrapper = new DozerBeanMapper(); ProductDTO pdt = new ProductDTO(); pdt.setIsConsignerCreditLimit(3); pdt.setLoanAction("323f3"); pdt.setProductName("feiwefe"); pdt.setPoundageRate("f332r3"); long beg = System.currentTimeMillis(); PropertyUtilsBean bean = new PropertyUtilsBean(); BeanCopier copier = BeanCopier.create(ProductDTO.class, LfProduct.class, false); for (int i=0;i<1000;i++) { LfProduct lfPdt = new LfProduct(); try { try { bean.copyProperties(lfPdt, pdt); } catch (IllegalAccessException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } // copier.copy(pdt, lfPdt, null); if (i==3) { // System.out.println(JacksonHelper.toJSON(lfPdt)); } // lfPdt = wrapper.map(pdt, LfProduct.class); lfPdt.setInputDate(new Date()); } System.out.println(System.currentTimeMillis() - beg);
240ms左右。
所以,因為絕大部分都是簡單的復制拷貝,這種情況下,BeanCopyer>PropertyUtils>Dozer。
參考:
http://blog.csdn.net/jianhua0902/article/details/8155368
http://blog.csdn.net/liangrui1988/article/details/41802275