当前位置: 首页 > 后端技术 > Java

为什么不推荐使用BeanUtils?

时间:2023-04-01 21:35:05 Java

作者:明明如月前辈\来源:blog.csdn.net/w605283073/article/details/107371462之前专栏说了“不推荐使用属性复制工具”,建议直接定义转换使用IDEA插件自动填充get/set函数的类和方法。不推荐的主要原因是:部分属性复制工具性能较差,部分属性复制工具存在“BUG”。使用属性拷贝工具存在一些隐患(后面的例子中会讲到)2例子先是在公司内部遇到了commons包的BeanUtils一个属性拷贝性能不佳的真实案例,后来同事换掉了使用Spring的BeanUtils,性能会好很多。有兴趣的可以使用性能测试框架或者benchmark测试框架进行对比,这里就不做对比了。接下来看看Spring的BeanUtils的属性拷贝会存在哪些问题:importlombok.Data;importjava.util.List;@DatapublicclassA{privateStringname;privateListids;}@DatapublicclassB{privateStringname;privateListids;}importorg.springframework.beans.BeanUtils;importjava.util.Arrays;publicclassBeanUtilDemo{publicstaticvoidmain(String[]args){Afirst=newA();}first.setName("演示");first.setIds(Arrays.asList(1,2,3));B第二=新B();BeanUtils.copyProperties(第一,第二);for(Stringeach:second.getIds()){//类型转换异常System.out.println(each);}}}当你运行上面的例子时,会发生类型转换异常。从断点可以看出,复制完属性后,第二个B类型对象中的id仍然是Integer类型:如果不转成字符串,可以直接打印,不会报错。在不定义Converter的情况下使用CGlib也会遇到类似的问题:;第一的。设置名称(“演示”);第一的。setIds(Arrays.asList(1,2,3));B第二=新B();最终BeanCopierbeanCopier=BeanCopier。创建(A.类,B.类,假);beanCopier.copy(first,second,null);for(Stringeach:second.getIds()){//类型转换异常System.out.println(each);}}}同样,问题只是在运行时暴露出来。接下来,让我们看一下mapstruct:BaToB(Acar);}importjava.util.Arrays;publicclassBeanUtilDemo{publicstaticvoidmain(String[]args){Afirst=newA();first.setName("演示");first.setIds(Arrays.asList(1,2,3));Bsecond=Converter.INSTANCE.aToB(first);for(Stringeach:second.getIds()){//正常System.out.println(each);}}}可以成功将List中的ListA转换为B中的List类型。我们看下面编译生成的Converter实际类:importjava.util.ArrayList;importjava.util.List;importjavax.annotation.Generated;importorg.springframework.stereotype.Component;@Generated(value="org.mapstruct.ap.MappingProcessor",comments="version:1.3.1.Final,compiler:javac,environment:Java1.8.0_202(OracleCorporation)")@ComponentpublicclassConverterImplimplementsConverter{@OverridepublicBaToB(Acar){if(car==null){返回null;}Bb=新B();b.setName(car.getName());b.setIds(integerListToStringList(car.getIds()));返回b;}protectedListintegerListToStringList(Listlist){if(list==null){returnnull;}Listlist1=newArrayList(list.size());for(Integerinteger:list){list1.add(String.valueOf(integer));}返回列表1;}}自动为我们转换,我们可能没有意识到类型不一致如果我们给类A添加一个String数字属性,给类B添加一个Long数字属性,当数字设置为非A时使用mapstrueect。NumberFormatException将是使用数字类型时报告。@OverridepublicBaToB(Acar){if(car==null){返回null;}Bb=新B();b.setName(car.getName());if(car.getNumber()!=null){//问题就在这里b.setNumber(Long.parseLong(car.getNumber()));}b.setIds(integerListToStringList(car.getIds()));returnb;}使用cglib默认不会映射number属性,B中的number为null。如果手动定义转换器,使用IDEA插件(如generateO2O)自动转换:publicfinalclassA2BConverter{publicstaticBfrom(Afirst){Bb=newB();b.setName(first.getName());b.setIds(first.getIds());返回b;}}这个问题在编码阶段可以很明显的发现:3结论由于Java中的泛型实际上是在编译时检查的,所以泛型在编译后就被抹掉了,导致运行时List和List都是List类型,可以正常分配。当使用许多属性映射工具时,这会导致在编译时出现不太明显的错误。mapstruct自定义注解处理器,可以在编译阶段读取映射两边的泛型,然后进行映射。但这种映射也很糟糕。有时候我们因为粗心等原因定义了错误的类型,它会自动帮我们转换,这样会带来很多副作用。之前对各种属性映射工具的性能进行了简单的比较,结果如下:因此,请谨慎使用属性转换工具。如果可以,建议自定义转换类,使用IDEA插件自动填充。效率也相当高。A或B中任意一个属性如果类型不匹配,甚至删除一个属性,在编译阶段都可以报错,直接调用getset效率也很高。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.20w程序员红包封面,快拿。..5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!