漫画:Java如何实现热更新?
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?命令來加載新的字節碼文件就可以實現熱更新了,但需要注意熱更新不能替換正在運行的方法,它只能修改方法內部的業務代碼,如果修改了類字段或者是更改了類方法,那么熱更新就會執行失敗。
最后的話原創不易,斥資找人畫了漫畫,看著老王認真的份上,點個「在看」再走唄,這是對我最大的支持與鼓勵,謝謝!往期推薦我寫了10年博客,卻被人說“不火”?我是這樣懟回去的?
鏈表竟然比數組慢了1000多倍?(動圖+性能評測)
關注下方二維碼,每一天都有干貨!
點亮“在看”,助我寫出更多好文!
總結
以上是生活随笔為你收集整理的漫画:Java如何实现热更新?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: String中删除空格的7种方法!
- 下一篇: JDK15正式发布,新增功能预览!