您好,登錄后才能下訂單哦!
這篇文章主要講解了“java類加載器與類的熱替換怎么實現(xiàn)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“java類加載器與類的熱替換怎么實現(xiàn)”吧!
任何一個使用到的Class,都需要被classLoader加載到JVM中,這個加載的過程,又分為
defineClass
loadClass
resolveClass
即根據(jù)提供的不同形式的class文件的內(nèi)容,轉(zhuǎn)化成一個Class,對其進行加載,鏈接。
而所謂的hotswap,就是使用新的代碼替換掉已經(jīng)加載的這個Class中的內(nèi)容。
我們這里使用Javassist來模擬類似的效果,通過動態(tài)的修改class內(nèi)某個方法的內(nèi)容,來實現(xiàn)熱替換的效果。
基本步驟:
先定義一個接口,包含一個方法,該方法內(nèi)的內(nèi)容在后面用于熱替換
定義一個接口的實現(xiàn)
在Servlet內(nèi)接收頁面上傳入的參數(shù),頁面上的參數(shù)內(nèi)容,則是具體上面接口定義方法及方法對應(yīng)的方法體內(nèi)容
在接收到參數(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)類的引用改成另一個。
在更新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()
該方法就所做的就是我們在Trace腳本里定義的內(nèi)容,比如上面,我們會在對應(yīng)java方法執(zhí)行時打印一行等號,其對應(yīng)的方法jvm指令如下:
而這個方法是如何和我們自己要監(jiān)控的方法聯(lián)系起來的呢?就是在我們的監(jiān)控方法第一行,增加了對于trace方法的調(diào)用。
感謝各位的閱讀,以上就是“java類加載器與類的熱替換怎么實現(xiàn)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對java類加載器與類的熱替換怎么實現(xiàn)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責(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)容。