JAVA字節(jié)碼文件操作技巧
你知道如何操作JAVA字節(jié)碼文件嗎,這里將介紹與操作Java字節(jié)碼有關(guān)的基本知識(shí)和操作Java字節(jié)碼的方法及Demo,首先我們來(lái)看一下AOP的概念,AOP是OOP的延續(xù),是AspectOrientedProgramming的縮寫(xiě),意思是面向方面編程。
如何操作JAVA字節(jié)碼文件
本文將介紹與操作Java字節(jié)碼有關(guān)的基本知識(shí)和操作Java字節(jié)碼的方法及Demo,談到操作Java字節(jié)碼,不能不談到AOP(AspectOrientedProgramming),下面來(lái)簡(jiǎn)單介紹一下:
AOP簡(jiǎn)介
AOP是OOP的延續(xù),是AspectOrientedProgramming的縮寫(xiě),意思是面向方面編程。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP可以說(shuō)也是這種目標(biāo)的一種實(shí)現(xiàn)。
AOP的一個(gè)典型應(yīng)用就是J2EE。J2EE應(yīng)用系統(tǒng)只有部署在J2EE容器中才能運(yùn)行,那么為什么劃分為J2EE容器和J2EE應(yīng)用系統(tǒng)?通過(guò)對(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)中分離出來(lái),形成一個(gè)通用的框架平臺(tái),而且,這些功能機(jī)制的設(shè)計(jì)開(kāi)發(fā)有一定難度,同時(shí)運(yùn)行的穩(wěn)定性和快速性都非常重要,必須經(jīng)過(guò)長(zhǎng)時(shí)間調(diào)試和運(yùn)行經(jīng)驗(yàn)積累而成,因此,形成了專門(mén)的J2EE容器服務(wù)器產(chǎn)品,如TomcatJBoss。
簡(jiǎn)單了解AOP后,再來(lái)了解一下AOP底層技術(shù):
AOP(AspectOrientedProgramming)底層技術(shù)比較
從上面的圖表中分析可以看到,對(duì)于一般的操作Java字節(jié)碼要求(實(shí)際上是能夠滿足筆者100%的要求),綜合考慮功能,性能,可用性,易用性,使用Java字節(jié)碼框架來(lái)操作Java字節(jié)碼是最佳的選擇。
下面來(lái)了解一下都有哪些開(kāi)源操作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é)碼操控框架能被用來(lái)動(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ù)來(lái)解析類中的所有元素:類名稱、方法、屬性以及Java字節(jié)碼(指令)。ASM從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據(jù)用戶要求生成新類。下圖對(duì)當(dāng)前接觸常用的操作Java字節(jié)碼框架進(jìn)行了一個(gè)比較:
#p#
ASM的幾個(gè)特性:
1.JAVABased.
ASM是基于JAVA的,即用JAVA實(shí)現(xiàn)的。
2.Visitor模式.
對(duì)于ASM來(lái)說(shuō),Javaclass被描述為一棵樹(shù);使用“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í)盡量減小的性能的損失(性能的損失是不可避免)。
這里來(lái)介紹一下ASM組成及順序圖:
Corepackage提供了一個(gè)讀寫(xiě)、修改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)換和用于簡(jiǎn)化bytecode生成的適配器。
Utilpackage包含了一些幫助類和簡(jiǎn)單的bytecode驗(yàn)證器,它們將有助于開(kāi)發(fā)或者測(cè)試。
XMLpackage提供了一個(gè)用于在bytecode和XML之間進(jìn)行轉(zhuǎn)換的適配器,和一些允許使用XSLT定義bytecode轉(zhuǎn)換的兼容SAX的適配器。
順序圖:
Demo
這里我們來(lái)實(shí)現(xiàn)這樣一個(gè)功能:在不能改變?cè)a功能的前提下,對(duì)于一個(gè)特定類的特定方法有沒(méi)有被測(cè)試過(guò),以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!”。#p#
下面我們來(lái)操作一下Java字節(jié)碼文件HelloTaobao.class:
1.想操作Java字節(jié)碼的某一方法,需要繼承ASM中的ClassAdapter和MethodAdapter
2.定義類Generator來(lái)讀入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類中重寫(xiě)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,
- Stringsignature,String[]exceptions)
- {
- MethodVisitormv=cv.visitMethod(access,name,desc,signature,
- exceptions);
- MethodVisitorwrappedMv=mv;
- if(mv!=null)
- {
- //對(duì)于”helloHeyun”方法進(jìn)行改造
- if(name.equals(“helloHeyun”))
- {
- //使用自定義MethodVisitor,改寫(xiě)方法內(nèi)容
- wrappedMv=newByteCodeMethodHandler(mv);
- }
- }
- returnwrappedMv;
- }
- }
5.ByteCodeMethodHandler(自定義)繼承MethodAdapter(fromASM),這里來(lái)做改造想要調(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來(lái)確定是兩個(gè)不同文件)。
8.此時(shí)在運(yùn)行主方法類Main,會(huì)發(fā)現(xiàn)在Console打印如下:
- Hello,ThisisHeyun’sinvestigationaboutcodecoverage!
- Thismethodhasalreadybeencovered.
9.由此,可以看出,在原功能沒(méi)有變化的前提下,通過(guò)改變Java字節(jié)碼文件,我們實(shí)現(xiàn)了CodeCoverage的雛形。實(shí)際上,很多CodeCoverage工具(如Cobertura)都是運(yùn)用此方法來(lái)實(shí)現(xiàn)Instrument(插裝)的。
【編輯推薦】
- IBM發(fā)布Java字節(jié)碼配置工具包BIPTK
- 深入學(xué)習(xí)JVM內(nèi)存設(shè)置原理和調(diào)優(yōu)
- JVM.dll裝載過(guò)程與源代碼分析
- 巧解使Eclipse崩潰的JVM terminated問(wèn)題
- 解決JVM Terminated.ExitCode=-1問(wèn)題行之有效的方法