java bean属性拷贝工具类比对(性能+功能)
业务系统中经常需要两个对象进行属性的拷贝,不能否认逐个的对象拷贝是最快速最安全的做法,但是当数据对象的属性字段数量超过程序员的容忍的程度比如通常超过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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2016-11-02 java线程控制、状态同步、volatile、Thread.interupt以及ConcurrentLinkedQueue
2016-11-02 java LinkedBlockingQueue和ConcurrentLinkedQueue的区别
2016-11-02 jvisualvm远程监控jvm设置