轉(zhuǎn)帖|其它|編輯:郝浩|2010-09-25 11:48:00.000|閱讀 727 次
概述:本文將介紹與操作Java字節(jié)碼有關(guān)的基本知識(shí)和操作Java字節(jié)碼的方法及Demo,談到操作Java字節(jié)碼,不能不談到AOP,這里向大家做一下簡單介紹。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
你知道如何操作JAVA字節(jié)碼文件嗎,這里將介紹與操作Java字節(jié)碼有關(guān)的基本知識(shí)和操作Java字節(jié)碼的方法及Demo,首先我們來看一下AOP的概念,AOP是OOP的延續(xù),是AspectOrientedProgramming的縮寫,意思是面向方面編程。
如何操作JAVA字節(jié)碼文件
本文將介紹與操作Java字節(jié)碼有關(guān)的基本知識(shí)和操作Java字節(jié)碼的方法及Demo,談到操作Java字節(jié)碼,不能不談到AOP(AspectOrientedProgramming),下面來簡單介紹一下:
AOP簡介
AOP是OOP的延續(xù),是AspectOrientedProgramming的縮寫,意思是面向方面編程。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP可以說也是這種目標(biāo)的一種實(shí)現(xiàn)。
AOP的一個(gè)典型應(yīng)用就是J2EE。J2EE應(yīng)用系統(tǒng)只有部署在J2EE容器中才能運(yùn)行,那么為什么劃分為J2EE容器和J2EE應(yīng)用系統(tǒng)?通過對(duì)J2EE容器運(yùn)行機(jī)制的分析,可以發(fā)現(xiàn):實(shí)際上J2EE容器分離了一般應(yīng)用系統(tǒng)的一些通用功能,例如事務(wù)機(jī)制、安全機(jī)制以及對(duì)象池或線程池等性能優(yōu)化機(jī)制。
這些功能機(jī)制是每個(gè)應(yīng)用系統(tǒng)幾乎都需要的,因此可以從具體應(yīng)用系統(tǒng)中分離出來,形成一個(gè)通用的框架平臺(tái),而且,這些功能機(jī)制的設(shè)計(jì)開發(fā)有一定難度,同時(shí)運(yùn)行的穩(wěn)定性和快速性都非常重要,必須經(jīng)過長時(shí)間調(diào)試和運(yùn)行經(jīng)驗(yàn)積累而成,因此,形成了專門的J2EE容器服務(wù)器產(chǎn)品,如TomcatJBoss。
簡單了解AOP后,再來了解一下AOP底層技術(shù):
AOP(AspectOrientedProgramming)底層技術(shù)比較
從上面的圖表中分析可以看到,對(duì)于一般的操作Java字節(jié)碼要求(實(shí)際上是能夠滿足筆者100%的要求),綜合考慮功能,性能,可用性,易用性,使用Java字節(jié)碼框架來操作Java字節(jié)碼是最佳的選擇。
下面來了解一下都有哪些開源操作JavaJava字節(jié)碼的框架:
Javassist;
cglib;
SERP;
Packagegnu.bytecode;
Cojen;
Jdec;
BCEL;
ObjectWebASM;
JClassLib;
TroveClassFileAPI;
Jiapi;
ClassfileReader&Writer;
JBET;
Retroweaver;
Jen;
Soot
這里重點(diǎn)介紹一下ASM,因?yàn)橄旅鎸⑹褂肁SM框架進(jìn)行Java字節(jié)碼修改。
ASM這個(gè)Java字節(jié)碼操控框架能被用來動(dòng)態(tài)生成類或者增強(qiáng)既有類的功能。ASM可以直接產(chǎn)生二進(jìn)制class文件,也可以在類被加載入Java虛擬機(jī)之前動(dòng)態(tài)改變類行為。Javaclass被存儲(chǔ)在嚴(yán)格格式定義的.class文件里,這些類文件擁有足夠的元數(shù)據(jù)來解析類中的所有元素:類名稱、方法、屬性以及Java字節(jié)碼(指令)。ASM從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。下圖對(duì)當(dāng)前接觸常用的操作Java字節(jié)碼框架進(jìn)行了一個(gè)比較:
ASM的幾個(gè)特性:
1.JAVABased.
ASM是基于JAVA的,即用JAVA實(shí)現(xiàn)的。
2.Visitor模式.
對(duì)于ASM來說,Javaclass被描述為一棵樹;使用“Visitor”模式遍歷整個(gè)二進(jìn)制結(jié)構(gòu)。
3.復(fù)雜性低.易學(xué)易用.
ASM提供了更為現(xiàn)代的編程模型,降低了操作Java字節(jié)碼的復(fù)雜性,使用事件驅(qū)動(dòng)的處理方式使得用戶只需要關(guān)注于對(duì)其編程有意義的部分,而不必了解Java類文件格式的所有細(xì)節(jié):ASM框架提供了默認(rèn)的“responsetaker”處理這一切。
4.較高的性能
對(duì)Java字節(jié)碼進(jìn)行操作的同時(shí)盡量減小的性能的損失(性能的損失是不可避免)。
這里來介紹一下ASM組成及順序圖:
Corepackage提供了一個(gè)讀寫、修改Javabytecode的API,并且為其它的package定義了依據(jù)。這個(gè)package對(duì)于生成Javabytecode、實(shí)現(xiàn)大多數(shù)的bytecode變換而言意義重大。
Treepackage提供了Javabytecode的內(nèi)存表示法。
Analysispackage提供了基本的數(shù)據(jù)流分析和類型檢查算法,它們將用于在treeoackage中存儲(chǔ)Java方法bytecode。
Commonspackage(包含在ASM2.0中)提供了一些常用的bytecode轉(zhuǎn)換和用于簡化bytecode生成的適配器。
Utilpackage包含了一些幫助類和簡單的bytecode驗(yàn)證器,它們將有助于開發(fā)或者測試。
XMLpackage提供了一個(gè)用于在bytecode和XML之間進(jìn)行轉(zhuǎn)換的適配器,和一些允許使用XSLT定義bytecode轉(zhuǎn)換的兼容SAX的適配器。
順序圖:
Demo
這里我們來實(shí)現(xiàn)這樣一個(gè)功能:在不能改變?cè)a功能的前提下,對(duì)于一個(gè)特定類的特定方法有沒有被測試過,以HelloTaobao類中方法helloHeyun為例。
類HelloTaobao:
publicclassHelloTaobao
{
publicvoidhelloHeyun()
{
System.out.println(“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”);
}
}
主方法類:
publicclassMain
{
publicstaticvoidmain(String[]args)
{
HelloTaobaoht=newHelloTaobao();
ht.heyunHeyun();
}
}
到這里,我們運(yùn)行一下程序,會(huì)在Console輸出字符串:“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”。
下面我們來操作一下Java字節(jié)碼文件HelloTaobao.class:
1.想操作Java字節(jié)碼的某一方法,需要繼承ASM中的ClassAdapter和MethodAdapter
2.定義類Generator來讀入Java字節(jié)碼文件HellTaobao,改造Java字節(jié)碼文件,生成改造后的同名Java字節(jié)碼文件HellTaobao,代碼如下:
publicclassGenerator
{
publicstaticvoidmain(String[]args)throwsException
{
ClassReadercr=newClassReader(“HellTaobao”);
ClassWritercw=newClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapterclassAdapter=newByteCodeClassHandler(cw);]
cr.accept(classAdapter,ClassReader.SKIP_DEBUG);
byte[]data=cw.toByteArray();
Filefile=newFile(“HellTaobao.class”);
FileOutputStreamfout=newFileOutputStream(file);
fout.write(data);
fout.close();
}
}
3.ByteCodeClassHandler(自定義)類繼承ClassAdapter(fromASM)
4.ByteCodeClassHandler類中重寫visitMethod,這個(gè)方法里去判斷如果Java字節(jié)碼文件HelloTaobao.class包含方法helloHeyun就調(diào)用ByteCodeMethodHandler類
publicclassByteCodeClassHandlerextendsClassAdapter
{
publicByteCodeClassHandler(ClassVisitorcv)
{
super(cv);
}
publicvoidvisit(intversion,intaccess,Stringname,Stringsignature,
StringsuperName,String[]interfaces)
{
super.visit(version,access,name,signature,superName,interfaces);
}
publicvoidvisitSource(Stringsource,Stringdebug)
{
super.visitSource(source,debug);
}
publicvoidvisitEnd()
{
}
@Override
publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,
publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,
{
MethodVisitormv=cv.visitMethod(access,name,desc,signature,
exceptions);
MethodVisitorwrappedMv=mv;
if(mv!=null)
{
//對(duì)于”helloHeyun”方法進(jìn)行改造
if(name.equals(“helloHeyun”))
{
//使用自定義MethodVisitor,改寫方法內(nèi)容
wrappedMv=newByteCodeMethodHandler(mv);
}
}
returnwrappedMv;
}
}
5.ByteCodeMethodHandler(自定義)繼承MethodAdapter(fromASM),這里來做改造想要調(diào)用的自定義方法,這里將調(diào)用類ControlByteCode(自定義)中的controlByteCodeByHeyun(自定義)方法
publicclassByteCodeMethodHandlerextendsMethodAdapter
{
publicByteCodeMethodHandler(MethodVisitormv)
{
super(mv);
}
publicvoidvisitCode()
{
visitMethodInsn(Opcodes.INVOKESTATIC,“ControlByteCode”,
“controlByteCodeByHeyun”,“()V”);
}
}
6.ControlByteCode類的controlByteCodeByHeyun方法如下
publicclassControlByteCode
{
publicstaticvoidcontrolByteCodeByHeyun()
{
System.out.println(“Thismethodhasalreadybeencovered.”);
//TODOrealsecuritycheck
}
}
7.這樣,當(dāng)運(yùn)行完Generator類中main方法后,會(huì)生成一個(gè)和原Java字節(jié)碼文件同名的文件(可以觀察出,會(huì)比以前的文件大,當(dāng)然也可以用MD5來確定是兩個(gè)不同文件)。
8.此時(shí)在運(yùn)行主方法類Main,會(huì)發(fā)現(xiàn)在Console打印如下:
Hello,ThisisHeyun’sinvestigationaboutcodecoverage!
Thismethodhasalreadybeencovered.
9.由此,可以看出,在原功能沒有變化的前提下,通過改變Java字節(jié)碼文件,我們實(shí)現(xiàn)了CodeCoverage的雛形。實(shí)際上,很多CodeCoverage工具(如Cobertura)都是運(yùn)用此方法來實(shí)現(xiàn)Instrument(插裝)的。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載