最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

我代碼就加了一行l(wèi)og日志,結果引發(fā)了P1的線上事故

2023-06-24 12:30 作者:劉姥姥看人間  | 我要投稿

線上事故回顧

前段時間新增一個特別簡單的功能,晚上上線前review代碼時想到公司拼搏進取的價值觀臨時加一行l(wèi)og日志,覺得就一行簡單的日志基本上沒啥問題,結果剛上完線后一堆報警,趕緊回滾了代碼,找到問題刪除了添加日志的代碼,重新上線完畢。

情景還原

定義了一個 CountryDTO

java復制代碼public class CountryDTO { ?? ?private String country; ? ? ?public void setCountry(String country) { ?? ? ? ?this.country = country; ?? ?} ? ? ?public String getCountry() { ?? ? ? ?return this.country; ?? ?} ? ? ?public Boolean isChinaName() { ?? ? ? ?return this.country.equals("中國"); ?? ?} }

定義測試類 FastJonTest

java復制代碼public class FastJonTest { ?? ?@Test ?? ?public void testSerialize() { ?? ? ? ?CountryDTO countryDTO = new CountryDTO(); ?? ? ? ?String str = JSON.toJSONString(countryDTO); ?? ? ? ?System.out.println(str); ?? ?} }

運行時報空指針錯誤:

通過報錯信息可以看出來是 ?序列化的過程中執(zhí)行了 isChinaName()方法,這時候this.country變量為空, 那么問題來了:

  • 序列化為什么會執(zhí)行isChinaName()呢?

  • 引申一下,序列化過程中會執(zhí)行那些方法呢?

源碼分析

通過debug觀察調用鏈路的堆棧信息


調用鏈中的ASMSerializer_1_CountryDTO.writeFastJson使用asm技術動態(tài)生成了一個類ASMSerializer_1_CountryDTO,

asm技術其中一項使用場景就是通過到動態(tài)生成類用來代替java反射,從而避免重復執(zhí)行時的反射開銷

JavaBeanSerizlier序列化原理

通過下圖看出序列化的過程中,主要是調用JavaBeanSerializer類的write()方法。

JavaBeanSerializer 主要是通過 getObjectWriter()方法獲取,通過對getObjectWriter()執(zhí)行過程的調試,找到比較關鍵的com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer方法,進而找到 com.alibaba.fastjson.util.TypeUtils#computeGetters

java復制代碼public static List<FieldInfo> computeGetters(Class<?> clazz, // ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? JSONType jsonType, // ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Map<String,String> aliasMap, // ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Map<String,Field> fieldCacheMap, // ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? boolean sorted, // ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? PropertyNamingStrategy propertyNamingStrategy // ?? ?){ ?? ? ? ?//省略部分代碼.... ?? ? ? ?Method[] methods = clazz.getMethods(); ?? ? ? ?for(Method method : methods){ ?? ? ? ? ? ?//省略部分代碼... ?? ? ? ? ? ?if(method.getReturnType().equals(Void.TYPE)){ ?? ? ? ? ? ? ? ?continue; ?? ? ? ? ? ?} ?? ? ? ? ? ?if(method.getParameterTypes().length != 0){ ?? ? ? ? ? ? ? ?continue; ?? ? ? ? ? ?} ?? ? ? ? //省略部分代碼... ?? ? ? ? ? ?JSONField annotation = TypeUtils.getAnnotation(method, JSONField.class); ?? ? ? ? ? ?//省略部分代碼... ?? ? ? ? ? ?if(annotation != null){ ?? ? ? ? ? ? ? ?if(!annotation.serialize()){ ?? ? ? ? ? ? ? ? ? ?continue; ?? ? ? ? ? ? ? ?} ?? ? ? ? ? ? ? ?if(annotation.name().length() != 0){ ?? ? ? ? ? ? ? ? ? ?//省略部分代碼... ?? ? ? ? ? ? ? ?} ?? ? ? ? ? ?} ?? ? ? ? ? ?if(methodName.startsWith("get")){ ?? ? ? ? ? ? //省略部分代碼... ?? ? ? ? ? ?} ?? ? ? ? ? ?if(methodName.startsWith("is")){ ?? ? ? ? ? ? //省略部分代碼... ?? ? ? ? ? ?} ?? ? ? ?} }

從代碼中大致分為三種情況:

  • @JSONField(.serialize = false, name = "xxx")注解

  • getXxx() : get開頭的方法

  • isXxx():is開頭的方法

序列化流程圖

示例代碼

java復制代碼/** ?* case1: @JSONField(serialize = false) ?* case2: getXxx()返回值為void ?* case3: isXxx()返回值不等于布爾類型 ?* case4: @JSONType(ignores = "xxx") ?*/ @JSONType(ignores = "otherName") public class CountryDTO { ?? ?private String country; ? ? ?public void setCountry(String country) { ?? ? ? ?this.country = country; ?? ?} ? ? ?public String getCountry() { ?? ? ? ?return this.country; ?? ?} ? ? ?public static void queryCountryList() { ?? ? ? ?System.out.println("queryCountryList()執(zhí)行!!"); ?? ?} ? ? ?public Boolean isChinaName() { ?? ? ? ?System.out.println("isChinaName()執(zhí)行!!"); ?? ? ? ?return true; ?? ?} ? ? ?public String getEnglishName() { ?? ? ? ?System.out.println("getEnglishName()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?public String getOtherName() { ?? ? ? ?System.out.println("getOtherName()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?/** ?? ? * case1: @JSONField(serialize = false) ?? ? */ ?? ?@JSONField(serialize = false) ?? ?public String getEnglishName2() { ?? ? ? ?System.out.println("getEnglishName2()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?/** ?? ? * case2: getXxx()返回值為void ?? ? */ ?? ?public void getEnglishName3() { ?? ? ? ?System.out.println("getEnglishName3()執(zhí)行!!"); ?? ?} ? ? ?/** ?? ? * case3: isXxx()返回值不等于布爾類型 ?? ? */ ?? ?public String isChinaName2() { ?? ? ? ?System.out.println("isChinaName2()執(zhí)行!!"); ?? ? ? ?return "isChinaName2"; ?? ?} }

運行結果為:

shell復制代碼isChinaName()執(zhí)行!! getEnglishName()執(zhí)行!! {"chinaName":true,"englishName":"lucy"}

代碼規(guī)范

可以看出來序列化的規(guī)則還是很多的,比如有時需要關注返回值,有時需要關注參數(shù)個數(shù),有時需要關注@JSONType注解,有時需要關注@JSONField注解;當一個事物的判別方式有多種的時候,由于團隊人員掌握知識點的程度不一樣,這個方差很容易導致代碼問題,所以盡量有一種推薦方案。 這里推薦使用@JSONField(serialize = false)來顯式的標注方法不參與序列化,下面是使用推薦方案后的代碼,是不是一眼就能看出來哪些方法不需要參與序列化了。

java復制代碼public class CountryDTO { ?? ?private String country; ? ? ?public void setCountry(String country) { ?? ? ? ?this.country = country; ?? ?} ? ? ?public String getCountry() { ?? ? ? ?return this.country; ?? ?} ? ? ?@JSONField(serialize = false) ?? ?public static void queryCountryList() { ?? ? ? ?System.out.println("queryCountryList()執(zhí)行!!"); ?? ?} ? ? ?public Boolean isChinaName() { ?? ? ? ?System.out.println("isChinaName()執(zhí)行!!"); ?? ? ? ?return true; ?? ?} ? ? ?public String getEnglishName() { ?? ? ? ?System.out.println("getEnglishName()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?@JSONField(serialize = false) ?? ?public String getOtherName() { ?? ? ? ?System.out.println("getOtherName()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?@JSONField(serialize = false) ?? ?public String getEnglishName2() { ?? ? ? ?System.out.println("getEnglishName2()執(zhí)行!!"); ?? ? ? ?return "lucy"; ?? ?} ? ? ?@JSONField(serialize = false) ?? ?public void getEnglishName3() { ?? ? ? ?System.out.println("getEnglishName3()執(zhí)行!!"); ?? ?} ? ? ?@JSONField(serialize = false) ?? ?public String isChinaName2() { ?? ? ? ?System.out.println("isChinaName2()執(zhí)行!!"); ?? ? ? ?return "isChinaName2"; ?? ?} }

三個頻率高的序列化的情況

以上流程基本遵循 發(fā)現(xiàn)問題 --> 原理分析 --> 解決問題 --> 升華(編程規(guī)范)。

  • 圍繞業(yè)務上:解決問題 -> 如何選擇一種好的額解決方案 -> 好的解決方式如何擴展n個系統(tǒng)應用;

  • 圍繞技術上:解決單個問題,順著單個問題掌握這條線上的原理。


我代碼就加了一行l(wèi)og日志,結果引發(fā)了P1的線上事故的評論 (共 條)

分享到微博請遵守國家法律
武威市| 台湾省| 宜宾市| 五大连池市| 阳朔县| 福鼎市| 大石桥市| 南充市| 宝山区| 平遥县| 泽普县| 乐山市| 湟中县| 偃师市| 杨浦区| 广宁县| 依安县| 兴安盟| 江川县| 砀山县| 乐都县| 阿合奇县| 衡山县| 景谷| 枣阳市| 客服| 岳西县| 民丰县| 漳州市| 定边县| 南靖县| 长丰县| 贵德县| 教育| 荔波县| 宁国市| 蓝田县| 金昌市| 武乡县| 德令哈市| 盱眙县|