在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一行log日志,引發了P1的線上事故

jf_ro2CN3Fa ? 來源:芋道源碼 ? 作者:芋道源碼 ? 2022-11-07 15:48 ? 次閱讀


線上事故回顧

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

基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

情景還原

?

定義了一個 CountryDTO

?

publicclassCountryDTO{
privateStringcountry;

publicvoidsetCountry(Stringcountry){
this.country=country;
}

publicStringgetCountry(){
returnthis.country;
}

publicBooleanisChinaName(){
returnthis.country.equals("中國");
}
}

?

定義測試類 FastJonTest

?

publicclassFastJonTest{
@Test
publicvoidtestSerialize(){
CountryDTOcountryDTO=newCountryDTO();
Stringstr=JSON.toJSONString(countryDTO);
System.out.println(str);
}
}

運行時報空指針錯誤:

64775822-5d7b-11ed-a3b6-dac502259ad0.png空指針

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

  • 序列化為什么會執行isChinaName()呢?
  • 引申一下,序列化過程中會執行那些方法呢?

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

源碼分析

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

652d8e80-5d7b-11ed-a3b6-dac502259ad0.png65920e46-5d7b-11ed-a3b6-dac502259ad0.jpg

調用鏈中的ASMSerializer_1_CountryDTO.writeFastJson使用asm技術動態生成了一個類ASMSerializer_1_CountryDTO

?

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

?

JavaBeanSerizlier序列化原理

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

65b3b3de-5d7b-11ed-a3b6-dac502259ad0.pngObjectSerializer實現類JavaBeanSerializer

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

publicstaticListcomputeGetters(Classclazz,//
JSONTypejsonType,//
MapaliasMap,//
MapfieldCacheMap,//
booleansorted,//
PropertyNamingStrategypropertyNamingStrategy//
){
//省略部分代碼....
Method[]methods=clazz.getMethods();
for(Methodmethod:methods){
//省略部分代碼...
if(method.getReturnType().equals(Void.TYPE)){
continue;
}
if(method.getParameterTypes().length!=0){
continue;
}
//省略部分代碼...
JSONFieldannotation=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開頭的方法

序列化流程圖

65d61064-5d7b-11ed-a3b6-dac502259ad0.png序列化流程圖

示例代碼

/**
*case1:@JSONField(serialize=false)
*case2:getXxx()返回值為void
*case3:isXxx()返回值不等于布爾類型
*case4:@JSONType(ignores="xxx")
*/
@JSONType(ignores="otherName")
publicclassCountryDTO{
privateStringcountry;

publicvoidsetCountry(Stringcountry){
this.country=country;
}

publicStringgetCountry(){
returnthis.country;
}

publicstaticvoidqueryCountryList(){
System.out.println("queryCountryList()執行!!");
}

publicBooleanisChinaName(){
System.out.println("isChinaName()執行!!");
returntrue;
}

publicStringgetEnglishName(){
System.out.println("getEnglishName()執行!!");
return"lucy";
}

publicStringgetOtherName(){
System.out.println("getOtherName()執行!!");
return"lucy";
}

/**
*case1:@JSONField(serialize=false)
*/
@JSONField(serialize=false)
publicStringgetEnglishName2(){
System.out.println("getEnglishName2()執行!!");
return"lucy";
}

/**
*case2:getXxx()返回值為void
*/
publicvoidgetEnglishName3(){
System.out.println("getEnglishName3()執行!!");
}

/**
*case3:isXxx()返回值不等于布爾類型
*/
publicStringisChinaName2(){
System.out.println("isChinaName2()執行!!");
return"isChinaName2";
}
}

運行結果為:

isChinaName()執行!!
getEnglishName()執行!!
{"chinaName":true,"englishName":"lucy"}

代碼規范

可以看出來序列化的規則還是很多的,比如有時需要關注返回值,有時需要關注參數個數,有時需要關注@JSONType注解,有時需要關注@JSONField注解;當一個事物的判別方式有多種的時候,由于團隊人員掌握知識點的程度不一樣,這個方差很容易導致代碼問題,所以盡量有一種推薦方案。

這里推薦使用@JSONField(serialize = false)來顯式的標注方法不參與序列化,下面是使用@JSONField注解后的代碼,是不是一眼就能看出來哪些方法不需要參與序列化了。

publicclassCountryDTO{
privateStringcountry;

publicvoidsetCountry(Stringcountry){
this.country=country;
}

publicStringgetCountry(){
returnthis.country;
}

@JSONField(serialize=false)
publicstaticvoidqueryCountryList(){
System.out.println("queryCountryList()執行!!");
}

publicBooleanisChinaName(){
System.out.println("isChinaName()執行!!");
returntrue;
}

publicStringgetEnglishName(){
System.out.println("getEnglishName()執行!!");
return"lucy";
}

@JSONField(serialize=false)
publicStringgetOtherName(){
System.out.println("getOtherName()執行!!");
return"lucy";
}

@JSONField(serialize=false)
publicStringgetEnglishName2(){
System.out.println("getEnglishName2()執行!!");
return"lucy";
}

@JSONField(serialize=false)
publicvoidgetEnglishName3(){
System.out.println("getEnglishName3()執行!!");
}

@JSONField(serialize=false)
publicStringisChinaName2(){
System.out.println("isChinaName2()執行!!");
return"isChinaName2";
}
}

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

65fbca66-5d7b-11ed-a3b6-dac502259ad0.png三個頻率高的序列化的情況

以上流程基本遵循,發現問題 --> 原理分析 --> 解決問題 --> 升華(編程規范)。

  • 圍繞業務上:解決問題 -> 如何選擇一種好的額解決方案 -> 好的解決方式如何擴展 n 個系統應用;
  • 圍繞技術上:解決單個問題,順著單個問題掌握這條線上的原理。

但其實這段代碼我并不滿意,原因是和 FastJson 依賴太高了。我想要的效果是,不依賴任何特定的 JSON 序列化框架。當我需要替換掉它的時候,隨時可以替換掉。

并且在寫代碼時,不要過于依賴日志。打日志只需要打緊要且關鍵的信息即可,不要什么日志都打,我曾見過一個系統,一個小時,把 128G 磁盤跑滿的管理系統。幾乎沒啥并發,但幾乎每個請求都輸出幾 M 的日志,這件事我后面會單獨拿出來講講。

關于@JSONField@JSONType等特性注解,后面我會在團隊內規范并給出新的解耦方案,把它們移除掉。



審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 代碼
    +關注

    關注

    30

    文章

    4829

    瀏覽量

    69069
  • 日志
    +關注

    關注

    0

    文章

    139

    瀏覽量

    10681

原文標題:一行log日志,引發了P1的線上事故

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux實時查看日志的四種命令詳解

    如何在Linux中實時查看日志文件的內容?那么有很多實用程序可以幫助用戶在文件更改或不斷更新時輸出文件的內容。在Linux中實時顯示文件內容的常用命令是tail命令(有效地管理文件)。 1
    的頭像 發表于 01-13 10:45 ?322次閱讀
    Linux實時查看<b class='flag-5'>日志</b>的四種命令詳解

    豐田汽車一行到訪中汽中心

    近日,豐田汽車株式會社(以下簡稱“豐田”)車輛開發中心中心長御沓悟司一行到訪中汽中心,與中汽中心黨委委員、副總經理李洧進行了座談交流。
    的頭像 發表于 01-09 10:56 ?149次閱讀

    玩轉Nginx日志管理:高效排查問題的終極指南

    Nginx日志對于統計、系統服務排錯很有用。Nginx日志主要分為兩種:access_log(訪問日志)和error_log(錯誤
    的頭像 發表于 12-30 13:50 ?194次閱讀

    TFP401AMP第一行丟失4個像素是什么原因導致的?

    PC送出來的HDMI信號通過TFP401AMP轉RGB后送到LCD,發現圖片第一行會有4個像素丟失,經過邏輯分析儀抓取HS信號發現:HS在DE信號low的時間段里周期為31.774
    發表于 12-30 08:39

    泰國國家石油一行到訪商湯科技

    近日,泰國國家石油有限公司董事長Chatchai Phromlert先生,首席執行官兼總裁Kongkrapan Intarajang先生率董事會到訪商湯科技,商湯科技副總裁、亞太業務事業群總裁史軍、亞太業務事業群副總裁鄒春慧等熱情接待了董事會一行
    的頭像 發表于 12-19 09:15 ?332次閱讀

    政府關懷 | 省、市、區領導干部一行蒞臨鑫金暉進行參觀調研

    11月14日,省、市、區領導干部一行蒞臨我司進行調研參觀,鐘瑞明董事長全程陪同參觀,深入溝通交流。領導一行深入生產車間,實地察看了生產現場情況,現場了解了鑫金暉的整體布局、運行情況以及發展理念。鐘瑞
    的頭像 發表于 11-23 01:07 ?395次閱讀
    政府關懷 | 省、市、區領導干部<b class='flag-5'>一行</b>蒞臨鑫金暉進行參觀調研

    nginx日志配置方法

    access_log用來定義日志級別,日志位置。
    的頭像 發表于 10-24 17:43 ?270次閱讀

    軟通動力領導一行訪問福州大學

    軟通動力高級副總裁王曉良、楊念農,軟通教育總裁林濤及福建新東湖集團有限公司董事長陳國平一行來訪福州大學。校黨委陳國龍書記在行政南樓會見了客人并座談交流,郭文忠副校長陪同會見。
    的頭像 發表于 10-10 10:43 ?547次閱讀

    RIMAC與IMD一行來訪聲揚科技,共話AI語音賦能產業升級

    科技聯合創始人、CTO陳東鵬博士等展開深入交流,共同探討AI語音技術在保險行業的創新應用。RIMAC與IMD一行來訪聲揚科技來訪中,RIMAC與IMD一行貴賓深入
    的頭像 發表于 09-30 10:56 ?757次閱讀
    RIMAC與IMD<b class='flag-5'>一行</b>來訪聲揚科技,共話AI語音賦能產業升級

    光伏互感器p1p2方向的區別

    光伏互感器是種用于測量光伏系統中電流和電壓的設備,它在光伏發電系統中起著至關重要的作用。光伏互感器的P1P2方向是指互感器的輸入端和輸出端的方向,它們對于互感器的正常工作和測量精度具有重要
    的頭像 發表于 08-21 18:21 ?2666次閱讀

    清華PE產投匯一行赴谷東科技考察與交流

    日前,PE產投匯一行赴國家級專精特新小巨人校友企業——谷東科技北京公司進行考察與交流。
    的頭像 發表于 08-13 09:45 ?655次閱讀

    在VSCODE終端make時遇到錯誤要一行一行看然后定位,可以直接跳轉點擊或者VSCODE定位錯誤嗎?

    每次在VSCODE終端make時遇到錯誤要一行一行看然后定位,可以直接跳轉點擊或者VSCODE直接定位錯誤嗎?能給個指引鏈接嗎?謝謝!
    發表于 06-25 07:37

    如何檢查日志中是否有類似cm_cy_log_msg( CYLF_MIDDLEWARE, CY_LOG_ERR) 的內容?

    運行,有什么方法可以檢查 cm_cy_log_msg 生成的日志? 像這樣: cm_cy_log_msg( CYLF_MIDDLEWARE, CY_LOG_ERR,\"Invalid
    發表于 05-31 12:45

    甘肅考察團一行蒞臨拓維信息參觀調研

    4月12至13日,甘肅考察團一行蒞臨拓維信息調研,深入
    的頭像 發表于 04-18 08:14 ?826次閱讀
    甘肅考察團<b class='flag-5'>一行</b>蒞臨拓維信息參觀調研

    STM32CUBEMX4.22.1在main函數里面添加一行語句就死機的原因?

    用STM32CUBEMX4.22.1版本,內嵌FREERTOS,想把4路ADC通過DMA方式采集,但是在main函數里面添加一行語句:HAL_ADC_Start_DMA( hadc1, ADC_DMA_Buf[0],4);后就死機了
    發表于 04-11 07:57
    主站蜘蛛池模板: se在线播放 | 色视频在线观看完整免费版 | 国产免费高清视频在线观看不卡 | 特级片免费看 | 99久久精品国产自免费 | 俺去鲁婷婷六月色综合 | 伊人久久综合网亚洲 | 免费人成a大片在线观看动漫 | 九月婷婷综合 | 亚洲成人在线网 | 狠狠色丁香婷婷综合欧美 | 欧美又粗又硬又大久久久 | 天天干视频在线观看 | 4438x成人全国最大 | 久久国产高清字幕中文 | 国产午夜精品久久理论片小说 | 无遮挡一级毛片视频 | 婷婷六| 五月天婷婷视频在线观看 | 欧美日韩高清一区 | 奇米网在线观看 | 看真人一一级毛片 | 天堂网在线最新版www中文网 | 美女午夜| 性欧美xxxx视频 | 超h高h文污肉 | 五月国产综合视频在线观看 | 美女被啪到哭网站在线观看 | 国产色爽女小说免费看 | 日日摸人人拍人人澡 | 奇米影视欧美 | 日韩在线视频免费观看 | 亚洲人xx视频 | 天堂资源在线8 | 在线亚洲小视频 | 在线观看免费av网站 | 日韩一级片免费看 | 农村妇女野外一级毛片 | 亚洲专区一路线二 | 日本a网站 | 九九全国免费视频 |