在一次迭代中,出現了一個低級錯誤,if
語句中的判斷邏輯出現了錯誤,恰好這個功能場景在開發和測試過程當中不多觸發,使用的用戶也很少,不過的確影響到了少部分用戶,因此仍是須要進行修復。html
想着只是更新一行代碼,若是走正常的發佈流程,須要經過如下步驟:java
提交代碼 -> 提測打包 -> 測試環境驗證 -> Release 環境驗證 -> 預發環境驗證 -> 線上環境git
若是你的應用體積不小,並且線上機器不少,花費的時間可能足夠喝不少杯 Java
:-Ogithub
以前使用過 Alibaba
開源的診斷工具 Arthas
,下圖是官方文檔中提到的功能:vim
不只能夠用來排查問題,還可以使用它 redefine
進行熱更新。bash
恰好以前也看到一篇文章介紹如何進行 一條龍更新
,因此就開始了嘗試,先從本地開發測試開始。jvm
開發時寫下的 java
程序是高級語言,須要經過編譯生成 .class
文件才能在 jvm
中運行。工具
因此在一個運行中的程序中進行熱更新,須要先將它使用 jad
[Java decompile]反編譯,修改 .java
文件後使用 mc
[Memory complile] 編譯出 .class
文件,最後使用 redefine
命令更新虛擬機中的程序。源碼分析
首先能夠跟着教程來一次嘗試 alibaba.github.io/arthas/arth…測試
# 反編譯
$ 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.class
redefine success, size: 1
複製代碼
跟着教程 demo
,發現代碼邏輯被修改,返回我修改後的結果,內心在狂喜,能夠不用喝這些多咖啡!
但在工做中的項目中使用,發現出現了這個問題:反編譯後的類不完整
查看經過 jad
命令反編譯後的文件:
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* ....
*/
複製代碼
在不完整的文件中進行修改後,進行 mc
命令編譯,將會提示以下:
[arthas@7281]$ mc -c 6bc28484 /tmp/xxxx.java -d /tmp
Memory compiler error, exception message: Compilation Error
......
, please check $HOME/logs/arthas/arthas.log for more details.
Affect(row-cnt:0) cost in 884 ms.
複製代碼
能夠看到,若是有複雜的類,並必定可以成功反編譯,遭遇了失敗,開始排查緣由
開源的好處的是,你們能夠一塊兒參與到其中,提出問題和解決問題,在 github
項目 arthas
的 issue
中,經過關鍵字 jad 反編譯
找到了緣由
可能好巧不巧,實際項目中的代碼,就趕上了這 1% 狀況(順便看了其它類,發現這種狀況還很多...)
當時對於 jad
機制是有點不瞭解,因此想先經過上面的提示的工具 dumpclass
去精確獲取 java
字節碼,但奈何有些難用,嘗試了幾遍仍是沒能拿下來,因而開始換種思路。
.class
文件既然前面的操做,獲取修改後的 .class
文件,都是爲了最後一步 redefine
所服務,那隻要獲取精確的 .class
文件就能夠了,跳過前面的步驟也能夠。
因而與一個前輩討論後,他建議我使用 IDEA
工具編譯後的 .class
文件
因而將本地代碼進行修改,進行打包編譯,獲得想要的 .class
文件,而後將這個文件上傳到測試環境,進行替換。
文件地址相似下圖:
[arthas@63]$ redefine /tmp/xxxxxx.class
redefine success, size: 1
複製代碼
出現了成功的提示,同時進行了接口測試,發現執行的代碼是修改後的邏輯!
經過上面說的,正常來講只須要簡單四步就能進行熱更新
1、使用 jad
反編譯出 .java
文件
2、編輯文件,修改邏輯
3、使用 mc
編譯修改後的文件
4、使用 redefine
熱更新
固然,也可能遇到 jad
反編譯失敗的場景,能夠參考方案二,直接拿到修改後的 .class
文件,而後繼續進行操做。
標題最後一個字爲何叫【誤】呢,是由於我通過測試,跟前輩們討論後,在發佈流程規範、 IDEA
提供的 .class
文件不肯定性還有工具誤用的把控上考慮,以爲目前不適合使用,因而仍是走了正常的發佈流程。
最後,Arthas提醒您: 診斷千萬條,規範第一條,熱更不規範,同事兩行淚
之後要避免再犯這些小錯誤,恩,換言之,我喝了不少杯 Java
:-(