色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

ASM2.0字節(jié)碼框架介紹

瀏覽:113日期:2024-07-19 16:47:51
內(nèi)容: 摘要:Java的特性如動(dòng)態(tài)類(lèi)加載和反射使其成為動(dòng)態(tài)語(yǔ)言。然而在許多時(shí)候,反射是不夠的,而且開(kāi)發(fā)人員需要從非Java源程序中生成字節(jié)碼,如腳本語(yǔ)言Groovy和BeanShell,或者源數(shù)據(jù)如ORM配置。當(dāng)使用已經(jīng)存在的類(lèi)時(shí),特別是當(dāng)沒(méi)有源程序時(shí),就需要使用一些工具來(lái)做如分析類(lèi)或方法的依賴(lài)性以便生成測(cè)試度量,或者來(lái)檢查是否存在問(wèn)題或反模式。Java5中增加了一些新特性,如如注解和范型,這會(huì)影響字節(jié)碼結(jié)果因而需要字節(jié)碼處理工具特別注意以便保持良好的性能。本文會(huì)通過(guò)一個(gè)最小且最快的Java字節(jié)碼處理框架來(lái)演示。版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必保留以下作者信息和鏈接作者:Eugene Kuleshov;xMatrix(作者的blog:http://blog.matrix.org.cn/page/xMatrix)原文:http://www.onjava.com/pub/a/onjava/2005/08/17/asm3.html譯文:http://www.matrix.org.cn/resource/article/44/44220_ASM+Bytecode+Framework.html關(guān)鍵字:ASM;Bytecode;Framework框架結(jié)構(gòu)ASM字節(jié)碼處理框架是用Java開(kāi)發(fā)的而且使用基于訪問(wèn)者模式生成字節(jié)碼及驅(qū)動(dòng)類(lèi)到字節(jié)碼的轉(zhuǎn)換。這允許開(kāi)發(fā)人員避免直接處理方法字節(jié)碼中的類(lèi)常量池及偏移,因此為開(kāi)發(fā)人員隱藏了字節(jié)碼的復(fù)雜性并且相對(duì)于其他類(lèi)似工具如BCEL, SERP, or Javassist提供了更好的性能。ASM分為幾個(gè)包更方便靈活地構(gòu)建。包結(jié)構(gòu)圖如圖1。 Figure 1. Arrangement of ASM packages·Core包提供了讀/寫(xiě)/轉(zhuǎn)換字節(jié)碼的API而且是其他包的基礎(chǔ)。這個(gè)包已經(jīng)足夠生成Java字節(jié)碼而且能夠?qū)崿F(xiàn)大部分的字節(jié)碼轉(zhuǎn)換。·Tree包提供了Java字節(jié)碼的內(nèi)存內(nèi)表示。·Analysis包為存儲(chǔ)在來(lái)自Tree包結(jié)構(gòu)中的Java方法字節(jié)碼提供了基礎(chǔ)的數(shù)據(jù)流分析和類(lèi)型檢查算法。·Commons包(ASM2.0增加)提供了幾個(gè)通用的字節(jié)碼轉(zhuǎn)換和簡(jiǎn)化字節(jié)碼生成的適配器。·Util包包含幾個(gè)助手類(lèi)和簡(jiǎn)單的字節(jié)碼較驗(yàn)器來(lái)方便開(kāi)發(fā)和測(cè)試。·XML包提供了與XML文件相互轉(zhuǎn)換的字節(jié)碼結(jié)構(gòu)適配器,及兼容SAX而且允許使用XSLT來(lái)定義字節(jié)碼轉(zhuǎn)換方式的適配器。后面幾節(jié)會(huì)給出ASM框架中Core包的介紹。為了更好地理解這個(gè)包的組織結(jié)構(gòu),你最好有一些在JVM規(guī)范中定義的字節(jié)碼結(jié)構(gòu)的基礎(chǔ)了解。下面是較高級(jí)別的類(lèi)文件格式圖([*]標(biāo)識(shí)重復(fù)的結(jié)構(gòu)) [1]-------------------------------------------+ | Header and Constant Stack | +--------------------------------------------+ | [*] Class Attributes | [2]------------+------------------------------+ | [*] Fields | Field Name, Descriptor, etc | | +------------------------------+ | | [*] Field Attributes | [3]------------+------------------------------+ | [*] Methods | Method Name, Descriptor, etc | | +------------------------------| | | Method max stack and locals | | |------------------------------| | | [*] Method Code table | | |------------------------------| | | [*] Method Exception table | | |------------------------------| | | [*] Method Code Attributes | | +------------------------------| | | [*] Method Attributes | +-------------+------------------------------+需要注意的一些地方:·所有使用在類(lèi)結(jié)構(gòu)中的描述符,字符串和其他常量都存儲(chǔ)在類(lèi)文件開(kāi)始的常量堆棧中,來(lái)自其他結(jié)構(gòu)的引用是基于堆棧的序號(hào)。·每一個(gè)類(lèi)必須包含頭部(包括類(lèi)名,父類(lèi),接口等)和常量堆棧。而其他元素如字段列表/方法列表/屬性列表都是可選的。·每一個(gè)方法段包含相同的頭信息和最大最小局部變量數(shù)的信息,這些是用來(lái)校驗(yàn)字節(jié)碼的。對(duì)非抽象和非原生方法,還包含一個(gè)方法指令表,一個(gè)異常表及代碼屬性。此外,還可能有其他的方法屬性。·類(lèi)的每一個(gè)屬性,成員/方法/方法代碼都有自己的名字,具體細(xì)節(jié)可參考JVM規(guī)范的類(lèi)文件格式部分。這些屬性代表字節(jié)碼的各種信息,如源文件名/內(nèi)部類(lèi)/標(biāo)識(shí)(用來(lái)存儲(chǔ)泛型)/行號(hào)/局部變量表和注解。JVM規(guī)范也允許定義自定義的屬性來(lái)包含更多的信息但標(biāo)準(zhǔn)實(shí)現(xiàn)的VM不會(huì)識(shí)別。注:Java5注解實(shí)際上已經(jīng)廢棄了那些自定義屬性,因?yàn)樽⒔庠谥髁x上允許你表達(dá)更多的東西。·方法代碼表包含JVM的指令列表。一些指令(就像異常/行號(hào)/局部變量表)使用代碼表中的偏移值并且所有這些偏移的值可能需要在指令從方法代碼表中增刪時(shí)相應(yīng)調(diào)整。如你所見(jiàn),字節(jié)碼轉(zhuǎn)換并不容易。但是,ASM框架減少了潛在的結(jié)構(gòu)復(fù)雜性并且提供簡(jiǎn)化的API允許所有字節(jié)碼信息的訪問(wèn)和復(fù)雜的轉(zhuǎn)換。基于事件的字節(jié)碼處理Core包使用推方案(類(lèi)似訪問(wèn)者模式,在SAX API就使用了這種模式處理XML)來(lái)遍歷復(fù)雜的字節(jié)碼結(jié)構(gòu)。ASM定義了幾個(gè)接口,如ClassVisitor,F(xiàn)ieldVisitor,MethodVisitor和AnnotationVisitor。AnnotationVisitor是一個(gè)特殊的接口允許你表達(dá)層次的注解結(jié)構(gòu)。下面的幾幅圖顯示這些接口是如何相互交互及配合使用實(shí)現(xiàn)字節(jié)碼轉(zhuǎn)換和從字節(jié)碼獲取信息。Core包邏輯上可憐分為兩大部分:1、 字節(jié)碼生產(chǎn)者,如ClassReader或者按正確順序調(diào)用了上面的訪問(wèn)者類(lèi)的方法的自定義類(lèi)。2、 字節(jié)碼消費(fèi)者,如輸出器(ClassWriter, FieldWriter, MethodWriter, and AnnotationWriter),適配器(ClassAdapter and MethodAdapter)或者其他實(shí)現(xiàn)了訪問(wèn)者接口的類(lèi)。圖2給出了通用生產(chǎn)者/消費(fèi)者交互過(guò)程的時(shí)序圖。Figure 2. Sequence diagram for producer-consumer interaction在這個(gè)交互過(guò)程中,客戶(hù)端應(yīng)用首先創(chuàng)建了ClassReader并調(diào)用accept()方法(以ClassVisitor實(shí)例作為參數(shù))。然后ClassReader解析類(lèi)并對(duì)每一個(gè)字節(jié)碼斷發(fā)送“visit事務(wù)給ClassVisitor。對(duì)循環(huán)的上下文,如成員/方法/注解,ClassVisitor可以創(chuàng)建繼續(xù)撲克相應(yīng)接口(FieldVisitor, MethodVisitor, or AnnotationVisitor)的子訪問(wèn)者并返回給生產(chǎn)者。如果生產(chǎn)者接收到一個(gè)空值,他簡(jiǎn)單地忽略類(lèi)的那部分(如在由訪問(wèn)者驅(qū)動(dòng)的“延遲加載特性時(shí)就不需要解析相應(yīng)的字節(jié)碼部分);否則相應(yīng)的子上下文事件就傳遞給子訪問(wèn)者實(shí)例。當(dāng)子上下文結(jié)束時(shí),生產(chǎn)者調(diào)用visitEnd()方法然后移到下一部分。字節(jié)碼消費(fèi)者可以通過(guò)手工傳遞事件給下一個(gè)鏈中的訪問(wèn)者或者使用來(lái)自傳遞所有訪問(wèn)方法給內(nèi)部的訪問(wèn)者的ClassAdapter/ MethodAdapter的訪問(wèn)者通過(guò)“響應(yīng)鏈模式連接起來(lái)。這些代理者一方面字節(jié)碼的消費(fèi)者方面另一方面也作為字節(jié)碼的生產(chǎn)者。他們?cè)趯?shí)現(xiàn)特定的字節(jié)碼轉(zhuǎn)換時(shí)可以修改原始的代理方式:1、 訪問(wèn)調(diào)用代理可以在刪除類(lèi)成員/方法/方法指令時(shí)被忽略。2、 訪問(wèn)調(diào)用參數(shù)可以在重命名類(lèi)/方法/類(lèi)型時(shí)被修改。3、 新訪問(wèn)調(diào)用可以在引入新成員/方法/注入新代碼到現(xiàn)存代碼時(shí)被增加。ClassWriter訪問(wèn)者可以終結(jié)整個(gè)處理鏈,他也是最終字節(jié)碼的生成者。例如: ClassWriter cw = new ClassWriter(computeMax); ClassVisitor cc = new CheckClassAdapter(cw); ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(System.out)); ClassVisitor cv = new TransformingClassAdapter(tv); ClassReader cr = new ClassReader(bytecode); cr.accept(cv, skipDebug); byte[] newBytecode = cw.toByteArray();在上面的代碼中,實(shí)現(xiàn)了自定義的類(lèi)轉(zhuǎn)換并且將結(jié)果人作為參數(shù)傳給TraceClassVisitor的構(gòu)造函數(shù)。TraceClassVisitor打印轉(zhuǎn)換的類(lèi)并傳遞給CheckClassAdapter(這是用來(lái)作簡(jiǎn)單的字節(jié)校驗(yàn)后傳遞給ClassWriter)。大部分的訪問(wèn)方法接收簡(jiǎn)單的參數(shù)如int,boolean和String。在所有的方法中String參數(shù)是字節(jié)碼中常量的引用,ASM使用與JVM一致的方式。例如,所有類(lèi)名都應(yīng)該定義在內(nèi)部格式中。成員和方法描述符應(yīng)該跟JVM表示一致。泛型信息的表示也類(lèi)似。這種方式避免了在沒(méi)有轉(zhuǎn)換時(shí)不必要的計(jì)算。為了便于構(gòu)建和解析這樣的描述,系統(tǒng)提供了包含一些靜態(tài)方法的Type類(lèi):·String getMethodDescriptor(Type returnType, Type[] argumentTypes)·String getInternalName(Class c)·String getDescriptor(Class c)·String getMethodDescriptor(Method m)·Type getType(String typeDescriptor)·Type getType(Class c)·Type getReturnType(String methodDescriptor)·Type getReturnType(Method m)·Type[] getArgumentTypes(String methodDescriptor)·Type[] getArgumentTypes(Method m)注意這些描述符使用了“簡(jiǎn)單表示,這意味著不包含泛型信息。泛型信息實(shí)際上作為一個(gè)單獨(dú)的字節(jié)屬性存儲(chǔ),但ASM專(zhuān)門(mén)對(duì)待這個(gè)屬性并且在相應(yīng)訪問(wèn)方法中傳遞泛型標(biāo)識(shí)串作為參數(shù)。這個(gè)標(biāo)識(shí)串的值也是參照J(rèn)VM規(guī)范,與Java代碼中的泛型定義唯一映射,并且為工具增加獲取額外細(xì)節(jié)的機(jī)會(huì)。ASM提供了與其他訪問(wèn)者類(lèi)似的SignatureVisitor, SignatureReader, and SignatureWriter類(lèi),如圖3所示。 Figure 3. Sequence diagram for Signature classesUtil包中包含了TraceSignatureVisitor,已經(jīng)實(shí)現(xiàn)了SignatureVisitor而且可以將一個(gè)標(biāo)識(shí)值轉(zhuǎn)換成Java的泛型定義。下面的例子將一個(gè)方法標(biāo)識(shí)轉(zhuǎn)換為Java方法定義。 TraceSignatureVisitor v = new TraceSignatureVisitor(access); SignatureReader r = new SignatureReader(sign); r.accept(v); String genericDecl = v.getDeclaration(); String genericReturn = v.getReturnType(); String genericExceptions = v.getExceptions(); String methodDecl = genericReturn + ' ' + methodName + genericDecl; if(genericExceptions!=null) { methodDecl += ' throws ' + genericExceptions; }到目前為止,我們已經(jīng)討論了ASM框架的基本設(shè)計(jì)方式及類(lèi)結(jié)構(gòu)處理。但最有趣的部分是ASM如何處理方法代碼。訪問(wèn)方法代碼在ASM中,方法定義是由ClassVisitor.visitMethod()來(lái)表示,剩下的方法字節(jié)碼則由MethodVisitor中的許多訪問(wèn)方法來(lái)表示。這些方法按照下面的順序來(lái)調(diào)用,“*表示重復(fù)的方法而“?表示方法只能被調(diào)用一次。此外,visit...Insn 和visitLabel方法必須按照訪問(wèn)代碼的字節(jié)碼指令順序調(diào)用,而visitTryCatchBlock, visitLocalVariable和visitLineNumber方法必須在標(biāo)簽作為參數(shù)傳遞被訪問(wèn)后才能調(diào)用。注意visitEnd方法必須在方法處理完成后被調(diào)用。雖然ClassReader已經(jīng)做了這一步,但在使用自定義字節(jié)碼生產(chǎn)者時(shí)要注意一點(diǎn)。還要注意如果一個(gè)方法包含字節(jié)碼(也就是說(shuō)方法是非抽象或非源生的),那么visitCode必須在第一個(gè)visit...Insn調(diào)用前被調(diào)用,而visitMaxs必須在最后一個(gè)visit...Insn調(diào)用后被調(diào)用。每一個(gè)visitIincInsn, visitLdcInsn, visitMultiANewArrayInsn, visitLookupSwitchInsn, and visitTableSwitchInsn方法唯一對(duì)應(yīng)一個(gè)字節(jié)碼指令。剩下的visit...Insn方法對(duì)應(yīng)多個(gè)字節(jié)碼指令,他們的操作碼作為第一個(gè)方法參數(shù)被傳入。所有這些操作碼常量被定義在Opcodes接口中。這種方式對(duì)字節(jié)碼的解析和格式化非常有效率。不幸的是,這給開(kāi)發(fā)人員生成非法代碼的可能,因?yàn)镃lassWriter不會(huì)校驗(yàn)這些限制。但是,還是有一個(gè)CheckClassAdapter可以被用來(lái)在開(kāi)發(fā)期間測(cè)試生成的代碼。另一個(gè)機(jī)會(huì)是對(duì)所有字節(jié)碼生成或轉(zhuǎn)換可以修改方法代碼的偏移并且在方法代碼中增刪額外的指令時(shí)應(yīng)該自動(dòng)調(diào)整。這對(duì)所有的跳轉(zhuǎn)偽指令的參數(shù)都兼容的,就如try-catch塊,行號(hào)和局部變量定義及一些特殊屬性一樣。但是,ASM為開(kāi)發(fā)人員隱藏了這些復(fù)雜性。為了定義方法字節(jié)碼中的位置且不需要使用絕對(duì)偏移值,需要傳遞一個(gè)唯一的標(biāo)簽類(lèi)的實(shí)例給visitLabel方法。其他MethodVisitor方法如visitJumpInsn, visitLookupSwitchInsn, visitTableSwitchInsn, visitTryCatchBlock, visitLocalVariable, and visitLineNumber可以使用這些標(biāo)簽實(shí)例在visitLabel調(diào)用之前,就像實(shí)例后在方法后被調(diào)用。上面的內(nèi)容看起來(lái)很復(fù)雜,好像需要很深?yuàn)W的字節(jié)碼指令知識(shí)。但是在編譯的類(lèi)上使用ASMifierClassVisitor就可以讓你知道如何用ASM生成給定的字節(jié)碼。此外,在兩個(gè)編譯的類(lèi)上(一個(gè)原始的和另一個(gè)應(yīng)用特定的轉(zhuǎn)換)使用然后進(jìn)行比較就可以給出什么樣的ASM調(diào)用應(yīng)該被使用在轉(zhuǎn)換器上。這個(gè)過(guò)程在幾篇文章中已經(jīng)詳細(xì)解釋了(可以參看最后的資源部分)。目前已經(jīng)有了Eclipse使用的插件了,如圖4,提供了從Java源生成ASM代碼及比較ASMifier輸出的良好支持,還包含了上下文字節(jié)碼的參考。 Figure 4. Eclipse ASM plugin (Click on the picture to see a full-size image)用ASM的訪問(wèn)者來(lái)跟蹤類(lèi)的依賴(lài)已經(jīng)有一些文章介紹了如何用ASM生成字節(jié)碼。現(xiàn)在,我們來(lái)看一下如何用ASM分析已有的類(lèi)。我們來(lái)做一個(gè)有趣的應(yīng)用來(lái)獲取給定的.jar文件中使用的外部類(lèi)和包。簡(jiǎn)單起見(jiàn),這個(gè)例子僅獲取外部的依賴(lài)而不會(huì)取依賴(lài)的類(lèi)型(如父類(lèi)/方法參數(shù)/局部變量類(lèi)型等)。僅為分析,我們不會(huì)創(chuàng)建那些注解/成員/方法的子訪問(wèn)者實(shí)例。所有使用的訪問(wèn)者(包括類(lèi)和標(biāo)識(shí)訪問(wèn)者)都在一個(gè)類(lèi)中實(shí)現(xiàn):public class DependencyVisitor implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor {...在這個(gè)例子中,我們會(huì)跟蹤包之間的依賴(lài),因此私有類(lèi)必須包含包名: private String getGroupKey(String name) { int n = name.lastIndexOf('/'); if(n>-1) name = name.substring(0, n); packages.add(name); return name; }為了獲取依賴(lài)關(guān)系,訪問(wèn)者接口如ClassVisitor, AnnotationVisitor, FieldVisitor, and MethodVisitor應(yīng)該選擇性地集成方法的參數(shù)。幾個(gè)常見(jiàn)的樣例如下: private void addName(String name) { if(name==null) return; String p = getGroupKey(name); if(current.containsKey(p)) { current.put(p, current.get(p)+1); } else { current.put(p, 1); } }在這個(gè)例子中,current是依賴(lài)的當(dāng)前包。另一個(gè)例子是類(lèi)型描述符(注解/枚舉/成員類(lèi)型/newarray指令的參數(shù)等);如Ljava/lang/String;, J, and [[[I。這些可以用Type.getType( desc)來(lái)獲取內(nèi)部格式的類(lèi)名: private void addDesc(String desc) { addType(Type.getType(desc)); } private void addType(Type t) { switch(t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getClassName().replace('.','/')); break; } }在方法定義中的方法描述法及激活指令中的描述參數(shù)類(lèi)型及返回類(lèi)型。可以通過(guò)Type.getReturnType(methodDescriptor) 和Type.getArgumentTypes(methodDescriptor)來(lái)解析并取得參數(shù)和返回類(lèi)型。 private void addMethodDesc(String desc) { addType(Type.getReturnType(desc)); Type[] types = Type.getArgumentTypes(desc); for(int i = 0; i < types.length; i++) { addType(types[ i]); } }而使用在許多“訪問(wèn)方法中的用來(lái)定義Java5泛型信息的標(biāo)識(shí)參數(shù)是個(gè)特例。如果存在,這個(gè)參數(shù)重寫(xiě)描述符參數(shù)并包含編碼后的泛型信息。可以被用SignatureReader來(lái)解析這個(gè)值。所以我們可以實(shí)現(xiàn)SignatureVisitor來(lái)被每一個(gè)標(biāo)識(shí)工件來(lái)調(diào)用。 private void addSignature(String sign) { if(sign!=null) { new SignatureReader(sign).accept(this); } } private void addTypeSignature(String sign) { if(sign!=null) { new SignatureReader(sign).acceptType(this); } }實(shí)現(xiàn)ClassVisitor接口的方法,如such as visit(), visitField(), visitMethod(), and visitAnnotation()就可以獲取在父類(lèi)/接口/成員類(lèi)型/方法參數(shù)/返回值/異常上的依賴(lài)信息,就如注解一樣。例如: public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { String p = getGroupKey(name); current = groups.get(p); if(current==null) { current = new HashMap(); groups.put(p, current); } if(signature==null) { addName(superName); addNames(interfaces); } else { addSignature(signature); } } public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if(signature==null) { addDesc(desc); } else { addTypeSignature(signature); } if(value instanceof Type) { addType((Type) value); } return this; } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if(signature==null) { addMethodDesc(desc); } else { addSignature(signature); } addNames(exceptions); return this; } public AnnotationVisitor visitAnnotation( String desc, boolean visible) { addDesc(desc); return this; }實(shí)現(xiàn)MethodVisitor接口的方法就可以獲取關(guān)于參數(shù)注解類(lèi)型和使用在可以使用對(duì)象引用的字節(jié)碼指令上的依賴(lài): public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { addDesc(desc); return this; } /** * Visits a type instruction * NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. */ public void visitTypeInsn(int opcode, String desc) { if(desc.charAt(0)=='[') { addDesc(desc); } else { addName(desc); } } /** * Visits a field instruction * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. */ public void visitFieldInsn(int opcode, String owner, String name, String desc) { addName(owner); addDesc(desc); } /** * Visits a method instruction INVOKEVIRTUAL, * INVOKESPECIAL, INVOKESTATIC or * INVOKEINTERFACE. */ public void visitMethodInsn(int opcode, String owner, String name, String desc) { addName(owner); addMethodDesc(desc); } /** * Visits a LDC instruction. */ public void visitLdcInsn(Object cst) { if(cst instanceof Type) { addType((Type) cst); } } /** * Visits a MULTIANEWARRAY instruction. */ public void visitMultiANewArrayInsn( String desc, int dims) { addDesc(desc); } /** * Visits a try catch block. */ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { addName(type); }現(xiàn)在我們可以用DependencyVisitor來(lái)獲取整個(gè).jar文件的依賴(lài)關(guān)系了。例如: DependencyVisitor v = new DependencyVisitor(); ZipFile f = new ZipFile(jarName); Enumeration<? extends ZipEntry> en = f.entries(); while(en.hasMoreElements()) { ZipEntry e = en.nextElement(); String name = e.getName(); if(name.endsWith('.class')) { ClassReader cr = new ClassReader(f.getInputStream(e)); cr.accept(v, false); } }可以用很多不同的方式來(lái)表示得到的信息。一種方式是構(gòu)建依賴(lài)樹(shù)并計(jì)算相關(guān)數(shù)據(jù)或者創(chuàng)建可視化的東西。例如,圖5顯示了ant1.6.5 jar包中的依賴(lài)關(guān)系的可視化表現(xiàn),這是我使用一些簡(jiǎn)單的Java2D代碼寫(xiě)的。下面的圖在水平軸上顯示包,在垂直軸上顯示依賴(lài)。陰影部分表示包被多次引用。 Figure 5. Dependencies in ant.1.6.5.jar, as discovered with ASM這個(gè)工具的全部代碼會(huì)被包含在下一個(gè)ASM發(fā)布中。你可以從ASM CVS獲取。ASM1.x后的改變?nèi)绻銢](méi)有使用ASM1.x可以略過(guò)這個(gè)段。2.0中主要的結(jié)構(gòu)變化是所有J2SE5.0的特性都被內(nèi)建到訪問(wèn)者/過(guò)濾器的事件流中。因此新的API允許你用更輕便和自然的方式來(lái)處理泛型和注解。不需要顯式創(chuàng)建注解屬性實(shí)例,因?yàn)樵谑录髦幸呀?jīng)包含了泛型和注解數(shù)據(jù)。例如,在1.x,ClassVisitor接口如下使用: CodeVisitor visitMethod(int access, String name, String desc, String[] exceptions, Attribute attrs);This has been split into several methods in ASM 2.0:在2.0中已經(jīng)分為多個(gè)方法: MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) AnnotationVisitor visitAnnotation(String desc, boolean visible) void visitAttribute(Attribute attr)在1.x API中,為了定義泛型信息,你必須創(chuàng)建SignatureAttribute的實(shí)例,而定義注解你需要RuntimeInvisibleAnnotations, RuntimeInvisibleParameterAnnotations, RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations, and AnnotationDefault的實(shí)例。然后你可以將這些實(shí)例放在相應(yīng)的訪問(wèn)方法的attrs參數(shù)中。在2.0,增加了新的標(biāo)識(shí)參數(shù)來(lái)表示泛型信息。新的AnnotationVisitor接口被用來(lái)處理所有的注解。不再需要?jiǎng)?chuàng)建attrs集合了,而且注解數(shù)據(jù)是強(qiáng)類(lèi)型的。然而在移植現(xiàn)有代碼時(shí),特別是在“適配器類(lèi)被使用時(shí),必須注意確保所有來(lái)自適配器的方法需要重寫(xiě)來(lái)適應(yīng)新的標(biāo)識(shí),因?yàn)榫幾g器不用對(duì)這種情況給出警告。ASM2.0還有些其他的改變。1、增加了新的接口FieldVisitor 和AnnotationVisitor2、CodeVisitor合并到MethodVisitor中了。3、在MethodVisitor中增加了visitCode()方法簡(jiǎn)化檢測(cè)首個(gè)指令。4、Constants接口重構(gòu)為Opcodes。5、所有來(lái)自attrs包的屬性被包含到ASM的事件模型中。6、TreeClassAdapter and TreeCodeAdapter被包含到ClassNode and MethodNode中。7、增加LabelNode類(lèi)使指令集合的元素成為AbstractInsnNode的通用類(lèi)型。通常,建議使用如JDiff這樣的工具來(lái)比較兩個(gè)版本之間的區(qū)別。小結(jié)ASM2.0為開(kāi)發(fā)人員屏蔽了字節(jié)碼的復(fù)雜性,因而使開(kāi)發(fā)人員更有效在字節(jié)碼級(jí)別上使用Java的特性。這個(gè)框架不僅允許你轉(zhuǎn)換和生成字節(jié)碼,而且可以從現(xiàn)有的類(lèi)中取得具體的信息。他的API繼續(xù)改善,現(xiàn)在已經(jīng)包含了J2SE5.0中的泛型和注解。接下來(lái),還會(huì)增加Mustang(J2SE6)中的新特性。資源·Java Virtual Machine Specification Java虛擬機(jī)規(guī)范&#8226;·'“修訂的類(lèi)文件格式(JVM規(guī)范的第4章)。包含J2SE5.0中支持的JSR-14/JSR-175/JSR-201中要求的修改及其他小的更正和調(diào)整。·“使用ASM工具集來(lái)處理字節(jié)碼·“使用ASM工具集來(lái)創(chuàng)建和讀寫(xiě)J2SE5.0注解·字節(jié)碼指令(BCI)。Eugene Kuleshov是一個(gè)獨(dú)立咨詢(xún)師,擁有超過(guò)15年的軟件設(shè)計(jì)開(kāi)發(fā)經(jīng)驗(yàn)。 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 摘要:Java的特性如動(dòng)態(tài)類(lèi)加載和反射使其成為動(dòng)態(tài)語(yǔ)言。然而在許多時(shí)候,反射是不夠的,而且開(kāi)發(fā)人員需要從非Java源程序中生成字節(jié)碼,如腳本語(yǔ)言Groovy和BeanShell,或者源數(shù)據(jù)如ORM配置。當(dāng)使用已經(jīng)存在的類(lèi)時(shí),特別是當(dāng)沒(méi)有源程序時(shí),就需要使用一些工具來(lái)做如分析類(lèi)或方法的依賴(lài)性以便生成測(cè)試度量,?
相關(guān)文章:
主站蜘蛛池模板: 91理论片午午伦夜理片久久 | 亚洲欧美日韩精品高清 | 成人高清视频免费观看 | 欧美日韩精品一区三区 | 一级aaa级毛片午夜在线播放 | 成年人毛片网站 | 久久超级碰 | 国产高清厕所盗摄视频 | 美女张开腿让男人桶爽免费网站 | 国产亚洲自在精品久久 | 一区二区三区欧美视频 | 国产精品毛片天天看片 | freesex日本高清nice | 3级毛片 | 日本暖暖视频在线播放 | 日日摸日日碰夜夜爽久久 | 日韩在线网 | 美国三级视频 | 欧美三级网站在线观看 | 久久黄色精品视频 | 一区二区三区视频 | 久久99久久99精品观看 | 国产成人久久精品推最新 | 高清午夜毛片 | 亚洲国产天堂在线网址 | 免费看欧美一级片 | 操爽视频| 国产成人一区二区三区 | 9191精品国产费久久 | 欧美一级专区免费大片俄罗斯 | 在线亚洲观看 | 亚洲1314 | 国产成人亚洲精品老王 | 日韩欧美在线看 | 成人99国产精品 | 欧美xxxxx九色视频免费观看 | 亚洲美女在线观看 | 亚洲视频 中文字幕 | 成人毛片免费观看视频在线 | 亚洲精品久久久久影 | 国产99视频免费精品是看6 |