进行判断使用class_记一次使用 Arthas 热更新线上代码
引用參考第二條 - Arthas提醒您: 診斷千萬(wàn)條,規(guī)范第一條,熱更不規(guī)范,同事兩行淚
起因
在一次迭代中,出現(xiàn)了一個(gè)低級(jí)錯(cuò)誤,if 語(yǔ)句中的判斷邏輯出現(xiàn)了錯(cuò)誤,剛好這個(gè)功能場(chǎng)景在開發(fā)和測(cè)試過(guò)程中很少觸發(fā),使用的用戶也不多,不過(guò)的確影響到了少部分用戶,所以還是需要進(jìn)行修復(fù)。
想著只是更新一行代碼,如果走正常的發(fā)布流程,需要通過(guò)以下步驟:
提交代碼 -> 提測(cè)打包 -> 測(cè)試環(huán)境git驗(yàn)證 -> Release 環(huán)境驗(yàn)證 -> 預(yù)發(fā)環(huán)境驗(yàn)證 -> 線上環(huán)境
如果你的應(yīng)用體積不小,而且線上機(jī)器很多,花費(fèi)的時(shí)間可能足夠喝很多杯 Java :-O
Arthas
之前使用過(guò) Alibaba 開源的診斷工具 Arthas ,下圖是官方文檔中提到的功能:
不僅可以用來(lái)排查問(wèn)題,還能夠使用它 redefine 進(jìn)行熱更新。
剛好之前也看到一篇文章介紹如何進(jìn)行 一條龍更新,所以就開始了嘗試,先從本地開發(fā)測(cè)試開始。
選擇方案
方案一:jad/mc/redefine線上熱更新一條龍
開發(fā)時(shí)寫下的 java 程序是高級(jí)語(yǔ)言,需要通過(guò)編譯生成 .class 文件才能在 jvm 中運(yùn)行。
所以在一個(gè)運(yùn)行中的程序中進(jìn)行熱更新,需要先將它使用 jad [Java decompile]反編譯,修改 .java 文件后使用 mc [Memory complile] 編譯出 .class 文件,最后使用 redefine 命令更新虛擬機(jī)中的程序。
首先可以跟著教程來(lái)一次嘗試 https://alibaba.github.io/arthas/arthas-tutorials?language=cn&id=arthas-advanced
# 反編譯$ jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java# 修改文件$ vim /tmp/UserController.java# 查找加載的 ClassLoader$ $ sc -d *UserController | grep classLoaderHash classLoaderHash 6bc28484# 編譯$ mc -c 6bc28484 /tmp/UserController.java -d /tmp# 熱更新$ redefine /tmp/com/example/demo/arthas/user/UserController.classredefine success, size: 1# 反編譯$ jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java# 修改文件$ vim /tmp/UserController.java# 查找加載的 ClassLoader$ $ sc -d *UserController | grep classLoaderHash classLoaderHash 6bc28484# 編譯$ mc -c 6bc28484 /tmp/UserController.java -d /tmp# 熱更新$ redefine /tmp/com/example/demo/arthas/user/UserController.classredefine success, size: 1跟著教程 demo,發(fā)現(xiàn)代碼邏輯被修改,返回我修改后的結(jié)果,心里在狂喜,可以不用喝這些多咖啡!
實(shí)際項(xiàng)目中反編譯失敗
但在工作中的項(xiàng)目中使用,發(fā)現(xiàn)出現(xiàn)了這個(gè)問(wèn)題:反編譯后的類不完整
查看通過(guò) jad 命令反編譯后的文件:
/* * Decompiled with CFR. * * Could not load the following classes: * .... */在不完整的文件中進(jìn)行修改后,進(jìn)行 mc 命令編譯,將會(huì)提示如下:
[arthas@7281]$ mc -c 6bc28484 /tmp/xxxx.java -d /tmpMemory compiler error, exception message: Compilation Error......, please check $HOME/logs/arthas/arthas.log for more details.Affect(row-cnt:0) cost in 884 ms.可以看到,如果有復(fù)雜的類,并一定能夠成功反編譯,遭遇了失敗,開始排查原因
反編譯失敗原因
開源的好處的是,大家可以一起參與到其中,提出問(wèn)題和解決問(wèn)題,在 github 項(xiàng)目 arthas 的 issue 中,通過(guò)關(guān)鍵字 jad 反編譯 找到了原因
橫云斷嶺 Arthas源碼分析–jad反編譯原理:
可能好巧不巧,實(shí)際項(xiàng)目中的代碼,就遇上了這 1% 情況(順便看了其它類,發(fā)現(xiàn)這種情況還不少…)
當(dāng)時(shí)對(duì)于 jad 機(jī)制是有點(diǎn)不了解,所以想先通過(guò)上面的提示的工具 dumpclass 去精確獲取 java 字節(jié)碼,但奈何有些難用,嘗試了幾遍還是沒(méi)能拿下來(lái),于是開始換種思路。
方案二:直接拿到 .class 文件
既然前面的操作,獲取修改后的 .class 文件,都是為了最后一步 redefine 所服務(wù),那只要獲取精確的 .class 文件就可以了,跳過(guò)前面的步驟也可以。
于是與一個(gè)前輩討論后,他建議我使用 IDEA 工具編譯后的 .class 文件
于是將本地代碼進(jìn)行修改,進(jìn)行打包編譯,得到想要的 .class 文件,然后將這個(gè)文件上傳到測(cè)試環(huán)境,進(jìn)行替換。
文件地址類似下圖:
[arthas@63]$ redefine /tmp/xxxxxx.classredefine success, size: 1出現(xiàn)了成功的提示,同時(shí)進(jìn)行了接口測(cè)試,發(fā)現(xiàn)執(zhí)行的代碼是修改后的邏輯!
總結(jié)
通過(guò)上面說(shuō)的,正常來(lái)說(shuō)只需要簡(jiǎn)單四步就能進(jìn)行熱更新
一、使用 jad 反編譯出 .java 文件
二、編輯文件,修改邏輯
三、使用 mc 編譯修改后的文件
四、使用 redefine 熱更新
當(dāng)然,也可能遇到 jad 反編譯失敗的場(chǎng)景,可以參考方案二,直接拿到修改后的 .class 文件,然后繼續(xù)進(jìn)行操作。
題外話
標(biāo)題最后一個(gè)字為什么叫【誤】呢,是因?yàn)槲医?jīng)過(guò)測(cè)試,跟前輩們討論后,在發(fā)布流程規(guī)范、 IDEA 提供的 .class 文件不確定性還有工具誤用的把控上考慮,覺(jué)得目前不適合使用,于是還是走了正常的發(fā)布流程。
最后,Arthas提醒您: 診斷千萬(wàn)條,規(guī)范第一條,熱更不規(guī)范,同事兩行淚
以后要避免再犯這些小錯(cuò)誤,恩,換言之,我喝了很多杯 Java :-(
參考資料
總結(jié)
以上是生活随笔為你收集整理的进行判断使用class_记一次使用 Arthas 热更新线上代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vue组件通信大总结
- 下一篇: android 本地提醒功能,andro