中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

酒店微信網(wǎng)站建設云優(yōu)化seo軟件

酒店微信網(wǎng)站建設,云優(yōu)化seo軟件,南通營銷平臺網(wǎng)站建設,東莞建站公司案例全網(wǎng)天下案例收錄于熱門專欄Java基礎教程系列(進階篇) 在實際的項目開發(fā)中,對象間賦值普遍存在,隨著雙十一、秒殺等電商過程愈加復雜,數(shù)據(jù)量也在不斷攀升,效率問題,浮出水面。 問:如果是你來寫…

收錄于熱門專欄Java基礎教程系列(進階篇)

在實際的項目開發(fā)中,對象間賦值普遍存在,隨著雙十一、秒殺等電商過程愈加復雜,數(shù)據(jù)量也在不斷攀升,效率問題,浮出水面。

問:如果是你來寫對象間賦值的代碼,你會怎么做?
答:想都不用想,直接代碼走起來,get、set即可。

問:下圖這樣?

在這里插入圖片描述

答:對啊,你怎么能把我的代碼放到網(wǎng)上?

問:沒,我只是舉個例子

答:這涉及到商業(yè)機密,是很嚴重的問題

問:我發(fā)現(xiàn)你挺能扯皮啊,直接回答問題行嗎?

答:OK,OK,我也覺得這樣寫很low,上次這么寫之后,差點挨打
對象太多,ctrl c + strl v,鍵盤差點沒敲壞;
而且很容易出錯,一不留神,屬性沒對應上,賦錯值了;
代碼看起來很傻缺,一個類好幾千行,全是get、set復制,還起個了自以為很優(yōu)雅的名字transfer;
如果屬性名不能見名知意,還得加上每個屬性的含義注釋(基本這種賦值操作,都是要加的,注釋很重要,注釋很重要,注釋很重要);
代碼維護起來很麻煩;
如果對象過多,會產(chǎn)生類爆炸問題,如果屬性過多,會嚴重違背阿里巴巴代碼規(guī)約(一個方法的實際代碼最多20行);
問:行了,行了,說說,怎么解決吧。

答:很簡單啊,可以通過工具類Beanutils直接賦值啊

問:我聽說工具類最近很卷,你用的哪個啊?
答:就Apache自帶的那個啊,賊簡單。我手寫一個,給你欣賞一下。
在這里插入圖片描述
問:你這代碼報錯啊,避免用Apache Beanutils進行屬性的copy。

答:沒報錯,只是嚴重警告而已,代碼能跑就行,有問題再優(yōu)化唄

問:你這什么態(tài)度?人事在哪劃拉的人,為啥會出現(xiàn)嚴重警告?
答:拿多少錢,干多少活,我又不是XXX,應該是性能問題吧

問:具體什么原因?qū)е碌哪?#xff1f;

答:3000塊錢還得手撕一下 apache copyProperties的源代碼唄?

通過單例模式調(diào)用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 提供了可以動態(tài)修改實現(xiàn)他的類的屬性名稱、屬性值、屬性類型的功能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);// 每個屬性都調(diào)用一次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赫然在列,穩(wěn)居耗時Top1。

問:還有其它好的方式嗎?性能好一點的
答:當然有,據(jù)我了解有 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);}
}

“四大金剛” 性能統(tǒng)計
在這里插入圖片描述

不測不知道,一測嚇一跳,差的還真的多。

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

性能走勢 --> spring cglib BeanCopier優(yōu)于 spring copyProperties優(yōu)于 apache PropertyUtils優(yōu)于 apache BeanUtils

避免用Apache Beanutils進行屬性的copy的問題 上面分析完了,下面再看看其它的方法做了哪些優(yōu)化。

Apache PropertyUtils 源碼分析
從源碼可以清晰的看到,類型檢查變成了非空校驗,去掉了每一次copy的日志記錄,性能肯定更好了。

類型檢查變成了非空校驗
去掉了每一次copy的日志記錄
實際賦值的地方由copyProperty變成了DanyBean + setSimpleProperty;
DanyBean 提供了可以動態(tài)修改實現(xiàn)他的類的屬性名稱、屬性值、屬性類型的功能。

public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {// 判斷數(shù)據(jù)源和目標對象不是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此處有優(yōu)化// DanyBean 提供了可以動態(tài)修改實現(xiàn)他的類的屬性名稱、屬性值、屬性類型的功能if (dest instanceof DynaBean) {((DynaBean)dest).set(name, value);} else {// 每個屬性都調(diào)用一次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 源碼分析
判斷數(shù)據(jù)源和目標對象的非空判斷改為了斷言;
每次copy沒有日志記錄;
沒有if (orig instanceof DynaBean) {這個類型檢查;
增加了放開權(quán)限的步驟;

private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,@Nullable String... ignoreProperties) throws BeansException {// 判斷數(shù)據(jù)源和目標對象不是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();/*** 源對象存在讀取方法、數(shù)據(jù)是可復制的* writeMethod.getParameterTypes()[0]:獲取 writeMethod 的第一個入?yún)㈩愋? readMethod.getReturnType():獲取 readMethod 的返回值類型* 判斷返回值類型和入?yún)㈩愋褪欠翊嬖诶^承關(guān)系,只有是繼承關(guān)系或相等的情況下,才會進行注入*/if (readMethod != null &&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {// 放開讀取方法的權(quán)限if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 通過反射獲取值Object value = readMethod.invoke(source);// 放開寫入方法的權(quán)限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);}}}}}
}
總結(jié)
阿里的友情提示,避免用Apache Beanutils進行對象的copy,還是很有道理的。Apache Beanutils的性能問題出現(xiàn)在類型校驗和每一次copy的日志記錄;Apache PropertyUtils 進行了如下優(yōu)化:
類型檢查變成了非空校驗
去掉了每一次copy的日志記錄
實際賦值的地方由copyProperty變成了DanyBean + setSimpleProperty;
Spring copyProperties 進行了如下優(yōu)化:
判斷數(shù)據(jù)源和目標對象的非空判斷改為了斷言;
每次copy沒有日志記錄;
沒有if (orig instanceof DynaBean) {這個類型檢查;
增加了放開權(quán)限的步驟;
http://www.risenshineclean.com/news/46738.html

相關(guān)文章:

  • 深圳網(wǎng)站制作hi0755營銷qq下載
  • 濟南 營銷型網(wǎng)站建設企業(yè)培訓課程
  • 有經(jīng)驗的網(wǎng)站建設公司seo優(yōu)化服務是什么意思
  • h5網(wǎng)站設計欣賞免費網(wǎng)站安全軟件大全
  • 學校網(wǎng)站建設招標方案百度知道首頁官網(wǎng)
  • 租用服務器建設網(wǎng)站費用win10優(yōu)化大師有用嗎
  • 德州做網(wǎng)站的競價托管服務多少錢
  • 無錫做公司網(wǎng)站的網(wǎng)絡搜索詞排名
  • 網(wǎng)站開發(fā)實用技術(shù)介紹南寧一站網(wǎng)網(wǎng)絡技術(shù)有限公司
  • 上海網(wǎng)站開發(fā)建優(yōu)秀的軟文廣告案例
  • 海淀區(qū)企業(yè)網(wǎng)站建設公司網(wǎng)站設計制作
  • 北京 順義 網(wǎng)站制作培訓網(wǎng)站制作
  • 自制圖片肇慶網(wǎng)站快速排名優(yōu)化
  • wordpress映射新余seo
  • 視頻解析接口網(wǎng)站怎么做百度提交網(wǎng)站
  • 怎么自己做三個一網(wǎng)站一份完整的營銷策劃書
  • 做農(nóng)產(chǎn)品的網(wǎng)站北京優(yōu)化seo排名優(yōu)化
  • 國外銷售網(wǎng)站怎樣建設免費長尾詞挖掘工具
  • 麗水專業(yè)網(wǎng)站建設哪家好抖音seo優(yōu)化
  • wordpress.conf網(wǎng)站seo優(yōu)化免費
  • 有沒有給做淘寶網(wǎng)站的中國十大網(wǎng)站有哪些
  • 做網(wǎng)站需要什么部門批準重慶seo優(yōu)化效果好
  • 濟寧做企業(yè)網(wǎng)站濟南網(wǎng)站優(yōu)化排名推廣
  • 在哪里做網(wǎng)站比較好十大廣告投放平臺
  • 做平臺和獨立建網(wǎng)站綜合型b2b電子商務平臺網(wǎng)站
  • 免費的素材網(wǎng)站網(wǎng)站如何做關(guān)鍵詞優(yōu)化
  • 個人網(wǎng)站發(fā)布怎么做優(yōu)化大師官網(wǎng)入口
  • 網(wǎng)站建設總體方案設計下載優(yōu)化大師app
  • web前端工程師職業(yè)規(guī)劃seo推廣優(yōu)化的方法
  • 公司網(wǎng)站建設有什么好處2345網(wǎng)址導航下載