当前位置: 首页 > news >正文

文广网站建设各大搜索引擎提交入口

文广网站建设,各大搜索引擎提交入口,徐州企业建站系统模板,外贸网络推广公司排名收录于热门专栏Java基础教程系列(进阶篇) 在实际的项目开发中,对象间赋值普遍存在,随着双十一、秒杀等电商过程愈加复杂,数据量也在不断攀升,效率问题,浮出水面。 问:如果是你来写…

收录于热门专栏Java基础教程系列(进阶篇)

在实际的项目开发中,对象间赋值普遍存在,随着双十一、秒杀等电商过程愈加复杂,数据量也在不断攀升,效率问题,浮出水面。

问:如果是你来写对象间赋值的代码,你会怎么做?
答:想都不用想,直接代码走起来,get、set即可。

问:下图这样?

在这里插入图片描述

答:对啊,你怎么能把我的代码放到网上?

问:没,我只是举个例子

答:这涉及到商业机密,是很严重的问题

问:我发现你挺能扯皮啊,直接回答问题行吗?

答:OK,OK,我也觉得这样写很low,上次这么写之后,差点挨打
对象太多,ctrl c + strl v,键盘差点没敲坏;
而且很容易出错,一不留神,属性没对应上,赋错值了;
代码看起来很傻缺,一个类好几千行,全是get、set复制,还起个了自以为很优雅的名字transfer;
如果属性名不能见名知意,还得加上每个属性的含义注释(基本这种赋值操作,都是要加的,注释很重要,注释很重要,注释很重要);
代码维护起来很麻烦;
如果对象过多,会产生类爆炸问题,如果属性过多,会严重违背阿里巴巴代码规约(一个方法的实际代码最多20行);
问:行了,行了,说说,怎么解决吧。

答:很简单啊,可以通过工具类Beanutils直接赋值啊

问:我听说工具类最近很卷,你用的哪个啊?
答:就Apache自带的那个啊,贼简单。我手写一个,给你欣赏一下。
在这里插入图片描述
问:你这代码报错啊,避免用Apache Beanutils进行属性的copy。

答:没报错,只是严重警告而已,代码能跑就行,有问题再优化呗

问:你这什么态度?人事在哪划拉的人,为啥会出现严重警告?
答:拿多少钱,干多少活,我又不是XXX,应该是性能问题吧

问:具体什么原因导致的呢?

答:3000块钱还得手撕一下 apache copyProperties的源代码呗?

通过单例模式调用copyProperties,但是,每一个方法对应一个BeanUtilsBean.getInstance()实例,每一个类实例对应一个实例,这不算一个真正的单例模式。

public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {BeanUtilsBean.getInstance().copyProperties(dest, orig);
}

性能瓶颈 --> 日志太多也是病
通过源码可以看到,每一个copyProperties都要进行多次类型检查,还要打印日志。

/*** org.apache.commons.beanutils.BeanUtils.copyProperties方法源码解析*/
public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {// 类型检查if (dest == null) {throw new IllegalArgumentException("No destination bean specified");} else if (orig == null) {throw new IllegalArgumentException("No origin bean specified");} else {// 打印日志if (this.log.isDebugEnabled()) {this.log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + ")");}int var5;int var6;String name;Object value;// 类型检查// DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能if (orig instanceof DynaBean) {// 获取源对象所有属性DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();DynaProperty[] var4 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {DynaProperty origDescriptor = var4[var6];// 获取源对象属性名name = origDescriptor.getName();// 判断源对象是否可读、判断目标对象是否可写if (this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {// 获取对应的值value = ((DynaBean)orig).get(name);// 每个属性都调用一次copyPropertythis.copyProperty(dest, name, value);}}} else if (orig instanceof Map) {Map<String, Object> propMap = (Map)orig;Iterator var13 = propMap.entrySet().iterator();while(var13.hasNext()) {Map.Entry<String, Object> entry = (Map.Entry)var13.next();String name = (String)entry.getKey();if (this.getPropertyUtils().isWriteable(dest, name)) {this.copyProperty(dest, name, entry.getValue());}}} else {PropertyDescriptor[] origDescriptors = this.getPropertyUtils().getPropertyDescriptors(orig);PropertyDescriptor[] var14 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {PropertyDescriptor origDescriptor = var14[var6];name = origDescriptor.getName();if (!"class".equals(name) && this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {try {value = this.getPropertyUtils().getSimpleProperty(orig, name);this.copyProperty(dest, name, value);} catch (NoSuchMethodException var10) {}}}}}
}

通过 jvisualvm.exe 检测代码性能
再通过jvisualvm.exe检测一下运行情况,果然,logging.log4j赫然在列,稳居耗时Top1。

问:还有其它好的方式吗?性能好一点的
答:当然有,据我了解有 4 种工具类,实际上,可能会有更多,话不多说,先简单介绍一下。
org.apache.commons.beanutils.BeanUtils;
org.apache.commons.beanutils.PropertyUtils;
org.springframework.cglib.beans.BeanCopier;
org.springframework.beans.BeanUtils;
问:那你怎么不用?
答:OK,我来演示一下

public class Test {public static void main(String[] args) {User user = new User();user.setUserId("1");user.setUserName("测试编程");user.setCardId("123");user.setCreateTime("2023-01-03");user.setEmail("666666666@qq.com");user.setOperate("测试");user.setOrgId("46987916");user.setPassword("123456");user.setPhone("10086");user.setRemark("456");user.setSex(1);user.setStatus("1");user.setTel("110");user.setType("0");user.setUpdateTime("2023-01-05");User target = new User();int sum = 10000000;apacheBeanUtilsCopyTest(user,target,sum);commonsPropertyCopyTest(user,target,sum);cglibBeanCopyTest(user,target,sum);springBeanCopyTest(user,target,sum);}private static void apacheBeanUtilsCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {apacheBeanUtilsCopy(source,target);}stopWatch.stop();System.out.println("使用org.apache.commons.beanutils.BeanUtils方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.apache.commons.beanutils.BeanUtils方式*/private static void apacheBeanUtilsCopy(User source, User target) {try {BeanUtils.copyProperties(source, target);} catch (Exception e) {}}private static void commonsPropertyCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {commonsPropertyCopy(source,target);}stopWatch.stop();System.out.println("使用org.apache.commons.beanutils.PropertyUtils方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.apache.commons.beanutils.PropertyUtils方式*/private static void commonsPropertyCopy(User source, User target) {try {PropertyUtils.copyProperties(target, source);} catch (Exception e) {}}private static void cglibBeanCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {cglibBeanCopy(source,target);}stopWatch.stop();System.out.println("使用org.springframework.cglib.beans.BeanCopier方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.springframework.cglib.beans.BeanCopier方式*/static BeanCopier copier = BeanCopier.create(User.class, User.class, false);private static void cglibBeanCopy(User source, User target) {copier.copy(source, target, null);}private static void springBeanCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {springBeanCopy(source,target);}stopWatch.stop();System.out.println("使用org.springframework.beans.BeanUtils.copyProperties方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.springframework.beans.BeanUtils.copyProperties方式*/private static void springBeanCopy(User source, User target) {org.springframework.beans.BeanUtils.copyProperties(source, target);}
}

“四大金刚” 性能统计
在这里插入图片描述

不测不知道,一测吓一跳,差的还真的多。

spring cglib BeanCopier性能最好,apache BeanUtils性能最差。

性能走势 --> spring cglib BeanCopier优于 spring copyProperties优于 apache PropertyUtils优于 apache BeanUtils

避免用Apache Beanutils进行属性的copy的问题 上面分析完了,下面再看看其它的方法做了哪些优化。

Apache PropertyUtils 源码分析
从源码可以清晰的看到,类型检查变成了非空校验,去掉了每一次copy的日志记录,性能肯定更好了。

类型检查变成了非空校验
去掉了每一次copy的日志记录
实际赋值的地方由copyProperty变成了DanyBean + setSimpleProperty;
DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能。

public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {// 判断数据源和目标对象不是nullif (dest == null) {throw new IllegalArgumentException("No destination bean specified");} else if (orig == null) {throw new IllegalArgumentException("No origin bean specified");} else {// 删除了org.apache.commons.beanutils.BeanUtils.copyProperties中最为耗时的log日志记录int var5;int var6;String name;Object value;// 类型检查if (orig instanceof DynaBean) {// 获取源对象所有属性DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();DynaProperty[] var4 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {DynaProperty origDescriptor = var4[var6];// 获取源对象属性名name = origDescriptor.getName();// 判断源对象是否可读、判断目标对象是否可写if (this.isReadable(orig, name) && this.isWriteable(dest, name)) {try {// 获取对应的值value = ((DynaBean)orig).get(name);// 相对于org.apache.commons.beanutils.BeanUtils.copyProperties此处有优化// DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能if (dest instanceof DynaBean) {((DynaBean)dest).set(name, value);} else {// 每个属性都调用一次copyPropertythis.setSimpleProperty(dest, name, value);}} catch (NoSuchMethodException var12) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var12);}}}}} else if (orig instanceof Map) {Iterator entries = ((Map)orig).entrySet().iterator();while(true) {Map.Entry entry;String name;do {if (!entries.hasNext()) {return;}entry = (Map.Entry)entries.next();name = (String)entry.getKey();} while(!this.isWriteable(dest, name));try {if (dest instanceof DynaBean) {((DynaBean)dest).set(name, entry.getValue());} else {this.setSimpleProperty(dest, name, entry.getValue());}} catch (NoSuchMethodException var11) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var11);}}}} else {PropertyDescriptor[] origDescriptors = this.getPropertyDescriptors(orig);PropertyDescriptor[] var16 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {PropertyDescriptor origDescriptor = var16[var6];name = origDescriptor.getName();if (this.isReadable(orig, name) && this.isWriteable(dest, name)) {try {value = this.getSimpleProperty(orig, name);if (dest instanceof DynaBean) {((DynaBean)dest).set(name, value);} else {this.setSimpleProperty(dest, name, value);}} catch (NoSuchMethodException var10) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var10);}}}}}}
}

通过 jvisualvm.exe 检测代码性能
再通过jvisualvm.exe检测一下运行情况,果然,logging.log4j没有了,其他的基本不变。
在这里插入图片描述
Spring copyProperties 源码分析
判断数据源和目标对象的非空判断改为了断言;
每次copy没有日志记录;
没有if (orig instanceof DynaBean) {这个类型检查;
增加了放开权限的步骤;

private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,@Nullable String... ignoreProperties) throws BeansException {// 判断数据源和目标对象不是nullAssert.notNull(source, "Source must not be null");Assert.notNull(target, "Target must not be null");/*** 若target设置了泛型,则默认使用泛型* 若是 editable 是 null,则此处忽略* 一般情况下editable都默认为null*/Class<?> actualEditable = target.getClass();if (editable != null) {if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() +"] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}// 获取target中全部的属性描述PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);// 需要忽略的属性List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);for (PropertyDescriptor targetPd : targetPds) {Method writeMethod = targetPd.getWriteMethod();// 目标对象存在写入方法、属性不被忽略if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {Method readMethod = sourcePd.getReadMethod();/*** 源对象存在读取方法、数据是可复制的* writeMethod.getParameterTypes()[0]:获取 writeMethod 的第一个入参类型* readMethod.getReturnType():获取 readMethod 的返回值类型* 判断返回值类型和入参类型是否存在继承关系,只有是继承关系或相等的情况下,才会进行注入*/if (readMethod != null &&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {// 放开读取方法的权限if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 通过反射获取值Object value = readMethod.invoke(source);// 放开写入方法的权限if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}// 通过反射写入值writeMethod.invoke(target, value);}catch (Throwable ex) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);}}}}}
}
总结
阿里的友情提示,避免用Apache Beanutils进行对象的copy,还是很有道理的。Apache Beanutils的性能问题出现在类型校验和每一次copy的日志记录;Apache PropertyUtils 进行了如下优化:
类型检查变成了非空校验
去掉了每一次copy的日志记录
实际赋值的地方由copyProperty变成了DanyBean + setSimpleProperty;
Spring copyProperties 进行了如下优化:
判断数据源和目标对象的非空判断改为了断言;
每次copy没有日志记录;
没有if (orig instanceof DynaBean) {这个类型检查;
增加了放开权限的步骤;
http://www.zhongyajixie.com/news/6024.html

相关文章:

  • 淘宝客 网站备案经典软文广告案例
  • 有哪些做政府网站的相关公司怎么找精准客户资源
  • 5000元网站seo推广推广一次多少钱
  • 网站搜索引擎优化的基本内容数据分析一般用什么软件
  • 怎样用网站做淘宝推广昆明网络推广方式有哪些
  • 网站建设需要多长时间百度百科官网入口
  • 哪些网站可以做养殖的广告国内新闻大事20条
  • 网站建设的销售渠道sem推广
  • 域名停靠app网站入口重庆seo服务
  • 昆明网站推广专员搜索引擎营销是什么
  • 公司网站工商备案怎么做拓客软件
  • 广 做网站蓝光电影下载100种找客户的方法
  • 博山区住房和城乡建设局网站全球十大搜索引擎排名
  • 国外网站要备案吗推广网站哪个好
  • bootstrap中文网站模板拼多多关键词优化是怎么弄的
  • 四川省建行网站百度推广一年多少钱
  • 苏州seo网站优化软件友情链接可以随便找链接加吗
  • 通过高新区网站建设seo网站分析
  • 房山网站建设公司网络营销推广软件
  • 济宁网站建设 帮站旺道seo推广有用吗
  • 购买一级域名做网站推广普通话宣传海报
  • 宇锋网站建设宁德市政府
  • 购买一级域名做网站长尾关键词排名系统
  • 在哪个网站找事做靠谱杭州企业seo
  • 做公众号的网站模板下载深圳营销型网站定制
  • 金华规划局网站开发区公司网站定制
  • 静态网站建设的技术运用在百度怎么发广告做宣传
  • 网站后台可改资料适合发表个人文章的平台
  • 聊城做网站推广可以发广告的100个网站
  • 怎么给一个花店做网站建设2024百度下载