Arthas(阿爾薩斯)是 Alibaba 開源的一款 Java 診斷工具,使用它我們可以監控和排查 Java 程序,然而它還提供了非常實用的 Java 熱更新功能。
所謂的 Java 熱更新是指在不重啓項目的情況下實現代碼的更新與替換。使用它可以實現不停機更新 Java 程序,尤其是對那些啓動非常耗時的 Java 項目來說,更是效果顯著。
Arthas 的使用其實非常簡單,它爲我們提供了一個 Jar 包,我們只需要把這個 Jar 下載到本地,然後運行這個 Jar 包就可以正常使用它的功能了。
Arthas 功能簡述
當你遇到以下類似問題而束手無策時,Arthas 可以幫助你解決(來自官方):
這個類從哪個 jar 包加載的?爲什麼會報各種類相關的 Exception?
我改的代碼爲什麼沒有執行到?難道是我沒 commit?分支搞錯了?
遇到問題無法在線上 debug,難道只能通過加日誌再重新發布嗎?
線上遇到某個用戶的數據處理有問題,但線上同樣無法 debug,線下無法重現!
是否有一個全局視角來查看系統的運行狀況?
有什麼辦法可以監控到JVM的實時運行狀態?
怎麼快速定位應用的熱點,生成火焰圖?
Arthas 支持 JDK 6+,支持 Linux/Mac/Winodws,它採用命令行交互模式,同時提供豐富的 Tab 自動補全功能,進一步方便進行問題的定位和診斷。
Arthas 使用
Arthas 的使用步驟如下。
步驟一:下載 Arthas
首先,我們先把 Arthas 的 Jar 包下載到本地,它的下載地址是:https://alibaba.github.io/arthas/arthas-boot.jar
步驟二:啓動 Arthas
我們只需要使用普通的 jar 包啓動命令:java -jar arthas-boot.jar
來啓動 Arthas 即可,啓動成功之後的運行界面如下:
如上圖所示則表示 Arthas 啓動成功。
小貼士:當我們運行 java -jar arthas-boot.jar 命令時,首先需要先切換目錄至該 jar 包的位置,才能正常的啓動 Arthas。
步驟三:運行 Arthas
當我們啓動完 Arthas 之後,根據上圖的提示,我們需要選擇一個要調試的 Java 進程,例如我們輸入“4”來監測我自己寫的一個 Java 測試程序,執行結果如下:
當出現 Arthas 的 logo 之後,表示 Arthas 正常加載了 Java 進程。
步驟四:操作 Arthas
當 Arthas 加載 Java 進程成功之後,我們就可以輸入相關的命令來查看相關的信息了。
假如我們把本地環境視爲生產服務器,我們此時需要查看某個運行的 Java 程序是否爲最新版的。
在沒有 Arthas 之前,我們通常的步驟是這樣的:
找到相應的 jar 包(或者 war 包);
將 jar 包(或者 war 包)下載到本地;
找出相應的類進行解壓操作;
然後將解壓的 class 文件拖拽到 Java 編譯器(Idea 或 Eclipse)中,查看是否爲最新的代碼。
但如果使用的是 Arthas,那麼我們就可以直接通過反編譯命令,將字節碼編譯爲正常的 Java 代碼,然後再確認是否爲最新的代碼即可。我們只需要執行 jad
命令即可,實現示例如下:
這樣我們就可以直接來查看這個發佈的程序是否爲最新版本了。
不僅如此,我們還可以使用 Arthas 來監測整個程序的運行情況,如下圖所示:
我們還可以用 Arthas 來查看一些 JVM 的相關信息,如下圖所示:
更多 Arthas 的功能,請訪問:https://alibaba.github.io/arthas/commands.html
熱更新 Java 代碼
假如我們原來的代碼是這樣的:
package com.example;
import java.util.concurrent.TimeUnit;
public class App {
public static void main(String[] args) throws InterruptedException {
while (true) { // 每兩秒鐘打印一條信息
TimeUnit.SECONDS.sleep(3);
sayHi();
}
}
private static void sayHi() {
// 需要修改的標識
boolean flag = true;
if (flag) {
System.out.println("Hello,Java.");
} else {
System.out.println("Hello,Java中文社羣.");
}
}
}
我們現在想要把 flag
變量改爲 false
就可以這樣來做:
使用 Arthas 的內存編譯工具將新的 Java 代碼編譯爲字節碼;
使用 Arthas 的
redefine
命令實現熱更新。
1.編譯字節碼
首先,我們需要將新的 Java 代碼編譯爲字節碼,我們可以通過 Arthas 提供的 mc
命令實現,mc
是 Memory Compiler(內存編譯器)的縮寫。
實現示例如下:
[arthas@3478]$ mc /Users/admin/Desktop/App.java -d /Users/admin/Desktop
Memory compiler output:
/Users/admin/Desktop/com/example/App.class
Affect(row-cnt:1) cost in 390 ms.
其中 -d
表示編譯文件的存放位置。
小貼士:我們也可以使用 javac App.java 生成的字節碼,它與此步驟執行的結果相同。
2.執行熱更新
有了字節碼文件之後,我們就可以使用 redefine
命令來實現熱更新了,實現示例如下:
[arthas@51787]$ redefine /Users/admin/Desktop/com/example/App.class
redefine success, size: 1
從上述結果可以看出,熱更新執行成功,此時我們去控制檯查看執行結果,如下圖所示:
這說明熱更新執行確實成功了。
Arthas 熱更新注意事項
使用熱更新功能有一些條件限制,我們只能用它來修改方法內部的一些業務代碼,如果我們出現了以下任意一種情況,那麼熱更新就會執行失敗:
增加類屬性(類字段);
增加或刪除方法;
替換正在運行的方法。
最後一條我們需要單獨說明一下,假如我們把上面的示例改爲如下代碼:
package com.example;
import java.util.concurrent.TimeUnit;
public class App {
public static void main(String[] args) throws InterruptedException {
while (true) { // 每兩秒鐘打印一條信息
TimeUnit.SECONDS.sleep(3);
boolean flag = true;
if (flag) {
System.out.println("Hello,Java.");
} else {
System.out.println("Hello,Java中文社羣.");
}
}
}
}
那麼此時我們再進行熱更新操作修改 flag
的值,那麼就會執行失敗,因爲我們替換的是正在運行中的方法,而我們正常示例中的代碼之所以能成功,是因爲我們在 while
無線循環中調用了另一個方法,而那個方法是被間歇性使用的,因此可以替換成功。
總結
本文我們講了 Arthas 的概念以及具體的使用流程,Arthas 其實就是一個普通的 Java 程序,我們可以使用 java -jar arthas-boot.jar
來啓動它,然後再選擇我們要操作的 Java 進程,這樣就可以實現狀態監控和其他操作。
文章的後半部分,我們介紹了 Arthas 的熱更新功能,而熱更新本質上只需要使用一個 redefine
命令來加載新的字節碼文件就可以實現熱更新了,但需要注意熱更新不能替換正在運行的方法,它只能修改方法內部的業務代碼,如果修改了類字段或者是更改了類方法,那麼熱更新就會執行失敗。
最後的話原創不易,斥資找人畫了漫畫,看着老王認真的份上,點個「在看」再走唄,這是對我最大的支持與鼓勵,謝謝!
往期推薦
關注下方二維碼,每一天都有乾貨!
點亮“在看”,助我寫出更多好文!