溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java類加載器與類的熱替換怎么實現(xiàn)

發(fā)布時間:2022-01-14 10:48:02 來源:億速云 閱讀:414 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“java類加載器與類的熱替換怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“java類加載器與類的熱替換怎么實現(xiàn)”吧!

任何一個使用到的Class,都需要被classLoader加載到JVM中,這個加載的過程,又分為

  1. defineClass

  2. loadClass

  3. resolveClass

即根據(jù)提供的不同形式的class文件的內(nèi)容,轉(zhuǎn)化成一個Class,對其進行加載,鏈接。

而所謂的hotswap,就是使用新的代碼替換掉已經(jīng)加載的這個Class中的內(nèi)容。

我們這里使用Javassist來模擬類似的效果,通過動態(tài)的修改class內(nèi)某個方法的內(nèi)容,來實現(xiàn)熱替換的效果。

java類加載器與類的熱替換怎么實現(xiàn)

基本步驟:

  1. 先定義一個接口,包含一個方法,該方法內(nèi)的內(nèi)容在后面用于熱替換

  2. 定義一個接口的實現(xiàn)

  3. 在Servlet內(nèi)接收頁面上傳入的參數(shù),頁面上的參數(shù)內(nèi)容,則是具體上面接口定義方法及方法對應(yīng)的方法體內(nèi)容

  4. 在接收到參數(shù)后,根據(jù)參數(shù)內(nèi)容,使用Javassist進行熱替換的操作。

基本Javassist的代碼大概是下面的樣子:

ITemp test = new Temp();  // 聲明一個接口

ClassPool pool = new ClassPool(true);


private ITemp hotswap(String str) {

        String methodBody = null;

        try {

 //添加到classpath

            pool.insertClassPath(new ClassClassPath(ITemp.class));

            String className = "ITemp_" + UUID.randomUUID();


            CtClass clazz = pool.makeClass(className);

            clazz.setInterfaces(new CtClass[]{pool.get("com.xxxx.ITemp")});

            methodBody = str;

            clazz.addMethod(CtMethod.make(methodBody, clazz));


            ITemp fun = (ITemp) clazz.toClass().newInstance();

            calculatorClass.writeFile("d:/temp");

            return fun;


            } catch(Exception e) {

            

            }

在用的過程中,接收到參數(shù)后,把hotswap方法返回的實例再指給test這個實例。然后test內(nèi)對應(yīng)方法的執(zhí)行已經(jīng)改成在頁面上傳入的邏輯。

原理

上面的是怎么樣實現(xiàn)的呢?

其實,上面的替換,實質(zhì)上,是重新生成了一個ITemp這個接口的實現(xiàn)類,然后我們在頁面上定義的,是這個實現(xiàn)類的方法中的內(nèi)容。然后我們的替換,是把一個實現(xiàn)類的引用改成另一個。

java類加載器與類的熱替換怎么實現(xiàn)

在更新Server中service的引用,指向新的實現(xiàn),舊的會在引用請求執(zhí)行完成后會被釋放。

另外一個

這時,一定有同學(xué)提起JDK默認支持的 Agent,這種基于JVMTI的實現(xiàn)。但是,這里需要注意的是,此時使用的是Agent,如果使用其pre_main,那么支持的是Class的 defineClass執(zhí)行前,對其進行所謂的增強或者是織入,類似于OpenJPA的Enhance和AJP的weave。

這種相當(dāng)于是把class內(nèi)容在讀到內(nèi)容之后修改了一下,然后傳給classLoader進行defineClass。

而JVMTI在JDK1.6之后,支持的另外一種形式,是在應(yīng)用已經(jīng)部署啟動之后,要進行類的改變的,使用的是agent_main方法,此時,需要對class進行retransform。像Java里一些常用的Profiler工具使用的就是這種,attach到已經(jīng)啟動的Java進程,對其進行retransform,例如Btrace。

這里的transform會調(diào)用Instrumention的RedefineClass,本質(zhì)上是修改類的定義。我們以Btrace為例,來看他在背后做了什么。

我的Trace腳本內(nèi)容如下:

@BTrace(unsafe=true)

public class TracingScript {

@OnMethod(clazz="com.xxx.WorkFun", method="myPrint")

public void sc() {

    println("===========");

  }

}

對于要監(jiān)控的類WorkFun,我們看到,Btrace監(jiān)控后,會類內(nèi)新增一個方法$btrace$TracingScript$sc()

java類加載器與類的熱替換怎么實現(xiàn)

該方法就所做的就是我們在Trace腳本里定義的內(nèi)容,比如上面,我們會在對應(yīng)java方法執(zhí)行時打印一行等號,其對應(yīng)的方法jvm指令如下:

java類加載器與類的熱替換怎么實現(xiàn)

而這個方法是如何和我們自己要監(jiān)控的方法聯(lián)系起來的呢?就是在我們的監(jiān)控方法第一行,增加了對于trace方法的調(diào)用。

java類加載器與類的熱替換怎么實現(xiàn)

感謝各位的閱讀,以上就是“java類加載器與類的熱替換怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對java類加載器與類的熱替換怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI