版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、簡(jiǎn)介在java開發(fā)領(lǐng)域,熱部署一直是一個(gè)難以解決的問題,口前的java虛擬機(jī)只能實(shí)現(xiàn)方法 體的修改熱部署,對(duì)于整個(gè)類的結(jié)構(gòu)修改,仍然需要重啟虛擬機(jī),對(duì)類重新加載才能完成更 新操作。對(duì)于某些人型的應(yīng)用來說,每次的重啟都需要花費(fèi)人量的時(shí)間成本。雖然osgi架 構(gòu)的出現(xiàn),讓模塊垂啟成為可能,但是如果模塊之間冇調(diào)川關(guān)系的話,這樣的操作依然會(huì)讓 應(yīng)用出現(xiàn)用桝的功能性休克。本文將探索如何在不破壞java虛擬機(jī)現(xiàn)有行為的前提下,實(shí) 現(xiàn)某個(gè)單一類的熱部署,讓系統(tǒng)無需重啟就完成某個(gè)類的更新。類加載的探索首先談一下何為熱部署(hotswap),熱部署是在不重啟java虛擬機(jī)的前提下,能占動(dòng)偵 測(cè)到class文件的
2、變化,更新運(yùn)行時(shí)class的行為。java類是通過java虛擬機(jī)加載的,某 個(gè)類的class文件在被classloadcr加載后,會(huì)生成對(duì)應(yīng)的class對(duì)象,之后就可以創(chuàng)建該 類的實(shí)例。默認(rèn)的虛擬機(jī)行為只會(huì)在啟動(dòng)時(shí)加載類,如果后期有一個(gè)類需要更新的話,單純 替換編譯的class文件,java虛擬機(jī)是不會(huì)更新正在運(yùn)行的class。如果要實(shí)現(xiàn)熱部署,最 根木的方式是修改虛擬機(jī)的源代碼,改變classloader的加載行為,使虛擬機(jī)能監(jiān)聽class文 件的更新,重新加載class文件,這樣的行為破壞性很大,為后續(xù)的jvm升級(jí)埋下了一個(gè) 大坑。另一種友好的方法是創(chuàng)建自己的classloader來加載需
3、要監(jiān)聽的class,這樣就能控制類加 載的時(shí)機(jī),從而實(shí)現(xiàn)熱部署。本文將具體探索如何實(shí)現(xiàn)這個(gè)方案。首先需要了解一下java虛 擬機(jī)現(xiàn)冇的加載機(jī)制。冃前的加載機(jī)制,稱為雙親委派,系統(tǒng)在使用一個(gè)classloader來加 載類時(shí),會(huì)先詢問當(dāng)前classloadcr的父類是否冇能力加載,如果父類無法實(shí)現(xiàn)加載操作, 才會(huì)將任務(wù)下放到該classloader來加載。這種自上而下的加載方式的好處是,讓每個(gè) classloadcr執(zhí)行自己的加載任務(wù),不會(huì)重復(fù)加載類。但是這種方式卻使加載順序非常難改變, 讓自定義classloader搶先加載需要監(jiān)聽改變的類成為了一個(gè)難題。不過我們可以換一個(gè)思路,雖然無法搶先加
4、載該類,但是仍然口j以川自定義classloader創(chuàng) 建一個(gè)功能相同的類,訃每次實(shí)例化的對(duì)象都指向這個(gè)新的類。當(dāng)這個(gè)類的class文件發(fā)& 改變的時(shí)候,再次創(chuàng)建一個(gè)更新的類,之后如果系統(tǒng)再次發(fā)出實(shí)例化請(qǐng)求,創(chuàng)建的対象講指 向這個(gè)全新的類。卜而來簡(jiǎn)單列舉一下需要做的工作。創(chuàng)建口定義的classloader,加載需要監(jiān)聽改變的類,在class文件發(fā)生改變的吋候,重 新加載該類。改變創(chuàng)建對(duì)象的行為,使他們?cè)趧?chuàng)建時(shí)使用自定義classloader加載的classo自定義加載器的實(shí)現(xiàn)自定義加載器仍然需要執(zhí)行類加載的功能。這里卻存在一個(gè)問題,同一個(gè)類加載器無法同時(shí) 加載兩個(gè)相同名稱的類,由于不論
5、類的結(jié)構(gòu)如何發(fā)生變化,生成的類名不會(huì)變,而classloader 只能在虛擬機(jī)停止前銷毀已經(jīng)加載的類,這樣classloader就無法加載更新后的類了。這里 有一個(gè)小技巧,讓每次加載的類都保存成一個(gè)帶有版本信息的class,比如加載test.class吋, 保存在內(nèi)存中的類杲test_vl.class,當(dāng)類發(fā)生改變時(shí),重新加載的類名是test_v2.classo但 是真止執(zhí)行加載class文件創(chuàng)建class的dcfincclass方法是一個(gè)native的方法,修改起來 又變得很因難。所以面前還剩一條路,那就是直接修改編譯生成的class文件。利用asm修改class文件 可以修改字節(jié)碼的框架有
6、很多,比如asm, cglibo本文使用的是asmo先來介紹一下 class文件的結(jié)構(gòu),class文件包含了以下兒類信息,一個(gè)是類的基本信息,包含了訪問權(quán)限 信息,類名信息,父類信息,接口信息。第二個(gè)是類的變量信息。第三個(gè)是方法的信息。asm會(huì)先加載一個(gè)class文件,然后嚴(yán)格順序讀取類的各項(xiàng)信息,用戶可以按照自己的意 愿定義增強(qiáng)組件修改這些信息,最后輸出成一個(gè)新的classo首先看一下如何利用asm修改類信息。清單1.利用asm修改字節(jié)碼classwriter cw = new classwriter(classwriter.<em>compute_maxs</em>
7、);classreader cr = null ;string enhancedclassname = classsource.getenhancedname();try cr = new classreader(new fileinputstream(classsource.getfile(); catch (ioexception e) e.printstacktrace();return null;classvisitor cv = new enhancedmodifier(cw, classname replace ( h . u , 11 /11) / enhancedclassna
8、me replace(” ” # " /n);craccept(cvz 0);asm修改字節(jié)碼文件的流程是一個(gè)責(zé)任鏈模式,首先使用一個(gè)classreader讀入字節(jié)碼, 然后利用classvisitor做個(gè)性化的修改,最后利用classwritcr輸出修改后的字節(jié)碼。z前提過,盂要將讀取的class文件的類名做一些修改,加載成一個(gè)全新名字的派生類。這 里將z分為了 2個(gè)步驟。笫一步,先將原來的類變成接口。清單2.重定義的原始類public class?>; redefineclass(string classname)classwriter cw = new classw
9、riter(classwritervem>compute_maxs</em>);classreader cr = null ;classsource cs = <em>classfiles</em> get(classname);if(cs=null)return null;try cr = new classreader(new fileinputstream(cs.getfile(); catch (ioexception e) e.printstacktrace();return null;classmodifier cm = new class
10、modifier(cw); craccept(cm, 0);byte code = cw.tobytearray();return defineclass(classname, coder 0, code.length);首先load原始類的class文件,此處定義了一個(gè)增強(qiáng)纟fl件classmodifier,作用是修改原 始類的類型,將它轉(zhuǎn)換成接口。原始類的所有方法邏輯都會(huì)被去掉。第二步,生成的派生類都實(shí)現(xiàn)這個(gè)接口,即原始類,并且復(fù)制原始類中的所有方法邏輯。z 后如果該類需要更新,會(huì)生成一個(gè)新的派住類,也會(huì)實(shí)現(xiàn)這個(gè)接口。這樣做的目的是不論如 何修改,同一個(gè)class的派生類都有一個(gè)共同的接口
11、,他們之間的轉(zhuǎn)換變得對(duì)外不透明。清單3.定義一個(gè)派生類/在class文件發(fā)生改變時(shí)重新定義這個(gè)類private class?>; redefineclass(string classname, classsource classso urce)classwriter cw = new classwriter(classwriter.vem>compute_maxs</em>);classreader cr = null ;classsource.update();string enhancedc1assname = classsource getenhancedn
12、ame();try cr = new classreader (new fileinputstreamclasssource.g巳tfile(); catch (ioexception e) e.printstacktrace();return null;enhancedmodi f ier em = new enhancedmodifier(cw, classname replace("enhancedclassname replace(” ",”/");extendmodifier exm = new extendmodifier(em, classname.
13、replace(”n/"),enhancedclassname. replace (” 11, " /n);cr.accept(exm, 0);byte code = cw.tobytearray();classsource setbytecopy(code);class?>; clazz = defineclass(enhancedclassname, code, 0, code len gth);classsource.setclasscopy(clazz);return clazz;再次load原始類的class文件,此處定義了兩個(gè)增強(qiáng)組件,一個(gè)是enha
14、ncedmodifier, 這個(gè)增強(qiáng)組件的作用是改變?cè)械念惷?。第二個(gè)增強(qiáng)組件是extendmodifier,這個(gè)增強(qiáng)組 件的作川是改變?cè)蓄惖母割悾屵@個(gè)修改后的派牛類能夠?qū)崿F(xiàn)同一個(gè)原始類(此時(shí)原始類 已經(jīng)轉(zhuǎn)成接口了)。自定義classloader還冇一個(gè)作川是監(jiān)聽會(huì)發(fā)生改變的class文件,classloader會(huì)管理一個(gè) 定時(shí)器,定吋依次掃描這些class文件是否改變。改變創(chuàng)建對(duì)象的行為java虛擬機(jī)常見的創(chuàng)建對(duì)象的方法有兩種,一種是靜態(tài)創(chuàng)建,直接new 個(gè)對(duì)象,一種是 動(dòng)態(tài)創(chuàng)建,通過反射的方法,創(chuàng)建對(duì)象。由于已經(jīng)在白定義加載器屮更改了原有類的類型,把它從類改成了接口,所以這兩種創(chuàng)建方
15、法都無法成立。我們要做的是將實(shí)例化原始類的行為變成實(shí)例化派生類。對(duì)于第一種方法,需要做的是將靜態(tài)創(chuàng)建,變?yōu)橥ㄟ^classloader獲取class,然后動(dòng)態(tài)創(chuàng)建 該對(duì)象。清單4.替換后的指令集所對(duì)應(yīng)的邏輯 /原始邏輯greeter p = new greeter();/改變后的邏輯igreeter p = (igreeter)myclassloadervem>getlnstance</em>().f indclass (ncom已xampl已grg0ter,') .newlnstance ();這里又需要用到asm來修改class文件了。查找到所冇new對(duì)象的語句,替
16、換成通過 classloader的形式來獲取對(duì)彖的形式。清單5.利用asm修改方法體©overridepublic void visittypelnsn(int opcode, string type) if(opcode=opcodes.<em>new</em> &;&; type.equals(classname)list;locaavariablenode> variables = node localvariablec);string compiletype = null ;for(int i = 0;i&am
17、p;it/variables size();i + +)local variablenode local variable = variables get:(i);compiletype = <em>formtype</em> (localvariable. desedi ) if (matchtype (compiletype) &; &; ! valiablelndexus valiablelndexusedi = true;break;mv.visitmethodlnsn(opcodes vemalnvokestaticv/em, &l
18、t;em>classload_type</em> z,getlnstancen , n ) l,+<em>classload_type</em>+n ; n );mv< visitldcinsn (type replace (11 /11 / n.n);mv.visitmethodlnsn(opcodes vemainvokevirtualv/em> z <em>classload_typ e</em>,hf indclass11 f h (ljava/lang/string;) ljava/lang/class;1
19、1);mv visitmethodlnsn (opcodes. <em>invokevirtual</em> z n j ava/lang/classii/hnewlnstance'1, n () ljava/lang/object ;n);mv.visittypeinsn(opcodes vemacheckcastv/em, compiletype);flag = true; else mv.visittypelnsn(opcoder type);對(duì)十第二種創(chuàng)建方法,需要通過修改class . f orname )和classloader. f indclas
20、s ()的彳丁為, 使他們通過口定義加載器加載類。使用javaagent攔截默認(rèn)加載器的行為之前實(shí)現(xiàn)的類加載器已經(jīng)解決了熱部署所需要的功能,可是jvm啟動(dòng)時(shí),并不會(huì)用自定 義的加載器加載classpath下的所有class文件,取而代z的是通過應(yīng)用加載器去加載。如 果在其z后川自定義加載器重新加載已經(jīng)加載的class,冇可能會(huì)出現(xiàn)linkageerror的 exceptiono所以必須在應(yīng)用啟動(dòng)z前,重新替換已經(jīng)加載的class如果在jdkl.4 z前,能 使用的方法只有一種,改變jdk中classloader的加載彳亍為,使它指向自定義加載器的加載 行為。好在jdk5.0之后,我們有了另一種
21、侵略性更小的辦法,這就是javaagent方法, javaagent nj'以在jvm啟動(dòng)z后,應(yīng)用啟動(dòng)z前的短暫間隙,提供空間給用戶做一些特姝 行為。比較常見的應(yīng)用,是利用javaagent做而向方而的編程,在方法間加入監(jiān)控日志等。javaagent的實(shí)現(xiàn)很容易,只要在一個(gè)類里而,定義一個(gè)premain的方法。清單6. 一個(gè)簡(jiǎn)單的javaagentpublic class reloadagent public static void premain(string agentargs, lnstrumentatio n inst)generaltransformer trans = n
22、ew generaltransformer();inst.addtransform已工(trans);然后編寫一個(gè)manifest文件,將premain-class屬性設(shè)置成定義一個(gè)擁冇premain方法的 類名即可。生成一個(gè)包含這個(gè)manifest文件的jar包。manifest-version: 10premain-class: com.example reloadagentcan-redefine-classes: true最后需要在執(zhí)行應(yīng)用的參數(shù)中增加- javaagent參數(shù),加入這個(gè)jar。同時(shí)可以為 javaagent增加參數(shù),下圖中的參數(shù)是測(cè)試代碼中test project的絕
23、対路徑。這樣在執(zhí)行應(yīng) 用的z前,會(huì)優(yōu)先執(zhí)行prewin方法中的邏輯,并且預(yù)解析需要加載的classo 圖1.增加執(zhí)行參數(shù)name test (1)q main (心 arguments 禺 jre% classpath耳/ source髡 environmenti e commonprogram arguments:vm arguments:-javaagent:c:/reloadagentjar=gwork5pacereload_cla55這里利m javaagent替換原始字節(jié)碼,阻止原始字節(jié)碼被java虛擬機(jī)加載。只需要實(shí)現(xiàn) 個(gè)classfiletransformer的接口,利丿ij這個(gè)
24、實(shí)現(xiàn)類完成class替換的功能。清單7.替換class©overridepublic byte transform(classloader paramclassloader, string paramstring,class;?>; paramclass. protectiondomain paramprotectiondomain,byte paramarrayofbyte) throws illegalclassformatexception string classname = paramstringreplace ,"u);if(classnameequals("com.example.test")myclassloader cl
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 貴州大學(xué)《機(jī)械制圖(二)》2023-2024學(xué)年第一學(xué)期期末試卷
- 貴陽學(xué)院《自動(dòng)控制原理C》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025黑龍江省安全員-B證考試題庫附答案
- 2025年上海建筑安全員考試題庫附答案
- 硅湖職業(yè)技術(shù)學(xué)院《廣播電視深度報(bào)道實(shí)務(wù)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025湖南建筑安全員B證考試題庫附答案
- 2025重慶市建筑安全員-B證(項(xiàng)目經(jīng)理)考試題庫
- 廣州幼兒師范高等專科學(xué)?!督ㄖ?、結(jié)構(gòu)識(shí)圖》2023-2024學(xué)年第一學(xué)期期末試卷
- 廣州新華學(xué)院《數(shù)字化模具設(shè)計(jì)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025重慶市安全員考試題庫
- 建筑公司證書津貼支付管理辦法
- 招標(biāo)代理機(jī)構(gòu)選取技術(shù)標(biāo)投標(biāo)方案(技術(shù)方案)
- 2024年電大勞動(dòng)與社會(huì)保障法期末考試題庫及答案
- 經(jīng)橈動(dòng)脈全腦血管造影術(shù)圍手術(shù)期護(hù)理
- 人教版九年級(jí)數(shù)學(xué)上冊(cè)21.1《一元二次方程》教學(xué)設(shè)計(jì)
- 從古至今話廉潔-大學(xué)生廉潔素養(yǎng)教育智慧樹知到期末考試答案章節(jié)答案2024年吉林大學(xué)
- 高中英語外刊-小貓釣魚50篇
- 開展醫(yī)院安全應(yīng)急演練工作計(jì)劃三篇
- 宜賓市敘州區(qū)2021-2022學(xué)年七年級(jí)上學(xué)期期末數(shù)學(xué)試題
- 【打油詩】72則創(chuàng)意期末評(píng)語模板-每頁8張
- 全國(guó)生態(tài)環(huán)境監(jiān)測(cè)專業(yè)技術(shù)人員大比武理論試題集 第八章 自動(dòng)監(jiān)測(cè)
評(píng)論
0/150
提交評(píng)論