更新時(shí)間:2022-06-15 10:25:44 來源:動(dòng)力節(jié)點(diǎn) 瀏覽3199次
Java熱更新是什么?動(dòng)力節(jié)點(diǎn)小編來告訴大家。在持續(xù)交付的時(shí)代,重新部署一個(gè)新的版本只需要點(diǎn)擊一下按鈕。但在有的情況下,重新部署過程可能比較復(fù)雜,停機(jī)是不被允許的。所以JVM提供了另外一種選擇:在不重啟應(yīng)用的前提下進(jìn)行小幅改動(dòng),又稱熱更新。
對于某些大型的應(yīng)用來說,每次的重啟都需要花費(fèi)大量的時(shí)間成本,所以,如果能在不重啟虛擬機(jī)的情況下更新一個(gè)類,在某些業(yè)務(wù)場景下變得十分重要。
在Java開發(fā)領(lǐng)域,熱更新一直是一個(gè)難以解決的問題,目前的Java虛擬機(jī)只能實(shí)現(xiàn)方法級別的熱更新,對于整個(gè)類的結(jié)構(gòu)修改,仍然需要重啟虛擬機(jī)。
Java熱更新一直不斷地改進(jìn)。
1.4開始JPDA引入了hotSwap機(jī)制(JPDA Enhancements),實(shí)現(xiàn)了debug時(shí)的method body的動(dòng)態(tài)性。
1.5開始通過JVMTI實(shí)現(xiàn)的java.lang.instrument(Java Platform SE 8)的premain方式,實(shí)現(xiàn)了agent方式的動(dòng)態(tài)性(JVM啟動(dòng)時(shí)指定agent)。
1.6增加了agentmain方式,實(shí)現(xiàn)了運(yùn)行時(shí)動(dòng)態(tài)性(通過The Attach API 綁定到具體VM)。其基本實(shí)現(xiàn)是通過JVMTI的retransformClass/redefineClass進(jìn)行函數(shù)體級別的字節(jié)碼更新,ASM、CGLib之類基本都是圍繞這些在做動(dòng)態(tài)性。
Tomcat的動(dòng)態(tài)部署就是監(jiān)聽war變化,然后調(diào)用StandardContext.reload(),用新的WebContextClassLoader實(shí)例來加載war,然后初始化servlet來實(shí)現(xiàn)。類似的實(shí)現(xiàn)還有OSGi等。
agentmain熱更新的原理
為了實(shí)現(xiàn)Java進(jìn)程A與進(jìn)程B之間的本地通信,熱更新的JVM進(jìn)程使用VirutalMachine.attach(pid)來連接需要熱更新的JVM進(jìn)程,然后使用virtualMachine.loadAgent加載自定義的agent(筆者查看了Arthas源碼,原理也大致相同)。這個(gè)通信通道成功建立之后,那么進(jìn)程A就能通知進(jìn)程B去執(zhí)行某些操作,從而達(dá)到監(jiān)控進(jìn)程B或者控制進(jìn)程B的某些行為的目的。如jstack、jmap等JDK自帶的工具,基本都是通過Attach機(jī)制去達(dá)成各自想要的目的的。
JVM啟動(dòng)的時(shí)候,在JVM內(nèi)部啟動(dòng)了一個(gè)監(jiān)聽線程,這個(gè)線程的名字叫“Signal Dispatcher”,該線程的作用是,監(jiān)聽并處理OS的信號。
arthas實(shí)現(xiàn)熱更新
使用Arthas三個(gè)命令就可以搞定熱更新
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
mc /tmp/UserController.java -d /tmp
redefine /tmp/com/example/demo/arthas/user/UserController.class
jad命令反編譯,然后可以用其它編譯器,比如vim來修改源碼
mc命令來內(nèi)存編譯修改過的代碼
用redefine命令加載新的字節(jié)碼
基于Attach機(jī)制實(shí)現(xiàn)的熱更新,更新類需要與原來的類在包名,類名,修飾符上完全一致,否則在classRedefine過程中會(huì)產(chǎn)生classname don't match 的異常。
例如顯示這樣的報(bào)錯(cuò):redefineClasses exception class redefinition failed: attempted to delete a method.
具體來說,JVM熱更新局限總結(jié):
函數(shù)參數(shù)格式不能修改,只能修改函數(shù)內(nèi)部的邏輯
不能增加類的函數(shù)或變量
函數(shù)必須能夠退出,如果有函數(shù)在死循環(huán)中,無法執(zhí)行更新類。
以上就是關(guān)于“一文讀懂Java熱更新”的介紹,大家如果想了解更多相關(guān)知識,可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java在線學(xué)習(xí),里面的課程內(nèi)容細(xì)致全面,從入門到精通,很適合沒有基礎(chǔ)的小伙伴學(xué)習(xí),希望對大家能夠有所幫助。
相關(guān)閱讀

初級 202925

初級 203221

初級 202629

初級 203743