业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度比如通常超过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配置映射,性能最低下):
org.dozer.DozerBeanMapper.map(Object source, Class<T> destinationClass)
就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