




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、使用代碼動態生成技術提升Java程序靈活性 摘 要: 代碼動態生成是指在程序運行時根據實際情況即時生成需要的類代碼。它可以提高程序的靈活性,已被用于很多應用架構、腳本語言的實現中。為幫助學生掌握代碼動態生成技術,探討了相關技術的實現方法、工具的應用和教學思路。 關鍵詞: 代碼動態生成; Java虛擬機; Java類文件; Bytecode; ASM 中圖分類號:TP311 文獻標志碼:A 文章編號:1006-8228(2013)05-07-03 Using code dynamic generation to enhance the flexibi
2、lity of Java programs Yan Zhonglin (College of information, mechanical and electrical engineering, Shanghai Normal University, Shanghai 200234, China) Abstract: Code dynamic generation is defined as class code generated instantly according to the actual needs when the program is running. It enhances
3、 the flexibility of the program, so it has been used in many framework and scripting language implementations. Students who are familiar with Java, JVM mechanism and Java class file structure will master this technique easily. It is beneficial for them to learn new concepts and new programming model
4、s based on this technology, which help them build more efficient, flexible and innovative application projects. The implementation methods, tools and teaching considerations are discussed. Key words: code dynamic generation; JVM; Java class files; Bytecode; ASM 0 引言 Java程序是通過JVM(Java虛擬機)運行的,JVM屏蔽了底層
5、硬件和操作系統的差異,提供了一個統一的處理平臺。JVM根據類文件執行運算,類文件含有數據定義和處理代碼,是Java程序的基本表示形式。程序中各個類文件分開存儲,運行時按需裝載鏈接,這一點和C+等其他語言不同。C+在編譯時就組合所有類,形成一個完整的可運行文件,而Java要直到運行時才動態組合,完成鏈接。 通常,類文件是由編譯器根據源文件自動生成,由JVM在運行時直接裝載的。但這不是獲得和使用它的惟一方法,某些情況下可以進行更巧妙的處理。比如在運行時繞過源文件直接生成需要的代碼,或者在裝載時直接修改類文件,即時改變它的行為,這就是類代碼動態生成技術。 類代碼動態生成技術需要直接在JVM的匯編語言
6、bytecode上展開工作。由于JVM模型和指令系統相對簡單,類文件有定義明確的格式和語義,成員描述、與其他類的關聯都基于符號引用,非常易于理解和修改,這都降低了直接處理它們的難度。這種類文件分開存儲、按需裝載的機制,也易于在運行時根據具體情況動態生成、替換某個特殊代碼段。這使我們有了在運行時改變程序行為的“魔力”,可以突破Java的某些限制,完成它本來無法實現的任務。 例如,作為靜態語言的Java,所有的域名、方法名都必須在編程時確定,有時這會限制程序的靈活性。雖然Java引入了“反射”機制以彌補此缺陷,但它的運行效率與正常代碼相差很多,將它應用于高頻執行的核心部分是不可接受的,這時就希望用
7、即時生成的、可高效執行的代碼進行替換。再比如,面向方面編程的實現需要在方法調用前后“編織”入橫切操作,這可以在編譯時進行,但如果能在運行時動態地插入這些代碼,無疑更具靈活性。對象/關系映射也與此類似,需要能即時生成與關系數據庫結構相對應的數據對象。這些都離不開代碼動態生成技術。 為適應技術的發展潮流,許多學校都開設有關Java高端應用的課程,如JavaEE,若干輕型架構,一些新型腳本語言等,它們會引入許多新概念和編程模式,如AOP、IOC、ORM等。要使學生切實領會和掌握這些抽象而微妙的內容,只作表面上的介紹往往是不夠的,應更深入地講解內部實現機制,使學生知其然,也知其所以然。如果做一些核查,
8、可以發現很多內容都離不開代碼動態生成,比較著名的就有AspectJ、Hibernate、Spring、Clojure、Groovy、JRuby、Jython、Eclipse等。由此可見,動態代碼生成已被相當普遍地使用了,可以認為它是未來Java高端項目開發的一種基本手段。因此,對現在的學生適當地普及這方面知識是很有必要的,這既可以使他們對Java特有的底層運行機制有更深入的理解,又可以幫助掌握許多現在流行的熱門技術,更重要的是為他們將來自己進行創新開發打下基礎。 要掌握這門技術,需要了解JVM的運行機制,這看起來比較困難,但由于Java是一個經過認真設計、非常理想化的平臺,相關內容從總體上說還
9、是易于理解和掌握的。經過對講授內容的規劃、斟酌,通常使用少量課時就能讓學生對此有較清晰的理解。接下來我們對相關的知識點和教學問題進行探討。 1 了解類文件格式 代碼動態生成技術要直接構造可裝載執行的類文件,因此首先必須清楚Java類文件的格式。它有非常明確的定義1(見圖1),除了文件頭部以外,還有以下各部分。 類型和接口部分:說明類的名字、訪問控制、父類以及所實現的所有接口。 數據域池:羅列了該類本身定義的所有數據成員,說明了各自的名字、訪問控制、類型、初始值等屬性。 方法域池:是它自身所有方法的集合,詳細描述了每個方法的名字、調用限制、參數類型、返回值、拋出異常、執行代碼等屬性。 類屬性池:
10、列出類相關的屬性,如源文件名等。整個文件中還有多處可出現各種屬性,用于表示各類專門信息。Java已定義了20種屬性,用戶也可以引入自己需要的新屬性。其中Annotation屬性比較值得關注,它用于支持各種元編程,結合這里介紹的代碼動態生成技術,可以實現各種特殊功能。 常量池:包含了所有常量,類名、域名、方法名等各種命名串,以及描述它們類型等屬性的描述串,對其他類的引用信息也在其中。常量共有14種類型,信息都用數字和字符表示,其他部分通過索引使用它們。 方法的“code”屬性的格式:它提供對應方法的bytecode代碼,try/catch塊位置,運行時操作棧和局部變量區等信息。類文件格式見圖1。
11、 類文件格式 /* u1 u2 u4為使用的字節數*/ 類文件標記:u4 0XCAFEBABE JDK版本: u2 子版本號; u2 主版本號 常量池: u2 常量池項數; 常量信息* 類型及接口:u2 訪問標志; u2 本類索引; u2 父類索引; u2 接口項數; u2 接口索引* 數據域池: u2 數據域項數; 數據信息* 方法域池: u2 方法域項數; 方法信息* 類屬性池: u2 類屬性項數; 類屬性信息* 數據信息 命名及描述:u2 訪問標志; u2 數據名索引; u2 數據描述串索引; 數據屬性池:u2 數據屬性項數; 數據屬性信息* 方法信息 命名及描述:u2 訪問標志; u2
12、 方法名索引; u2 方法描述串索引; 方法屬性池:u2 方法屬性項數; 方法屬性信息* 屬性信息 u2 屬性名索引; u4 屬性敘述長度; 屬性敘述 常量信息 u1 常量類型號; 常量敘述 Code信息 運行幀: u2 操作堆棧區大小; u2 局部變量區大小; 代碼塊: u4 代碼塊長度; bytecode代碼* 異常處理池:u2 處理塊項數; u2 起始點; u2終止點; u2處理點; u2 異常類型* 代碼屬性池:u2 代碼屬性項數; 代碼屬性信息* 圖1 類文件格式 類文件結構雖然有點復雜,但學生只需粗略了解,使用后面介紹的ASM進行處理,內部細節是可以忽略的。 2 使用ASM 類文件
13、是一個二進制文件,要程序員直接閱讀和編寫,是很困難的,應使用一些輔助工具軟件。目前這方面最成熟、最受歡迎的是ASM,它是一個開源軟件,相比于其他類似軟件,ASM 更小更快,也提供了更好的編程模型3。它還附有代碼生成工具和eclipse插件,可以在良好的人機界面下開展工作。ASM提供了兩套API,一套類似于處理XML文件的SAX,由掃描類文件產生的一系列事件驅動,采用訪問者模式進行處理。另一套類似于DOM,基于掃描類文件獲得的語法樹進行處理,兩套方法各有優缺點,前者速度快,所需內存少,而后者能進行更全面的控制。 以前套方法為例,ASM提供了類解析器ClassReader,能夠掃描解析類文件,并發
14、出各驅動事件;提供類生成器ClassWriter,按合適的次序調用能生成包含各種元素的二進制類文件。ASM還有ClassVisitor、FieldVisitor、MethodVisitor、AnnotationVisitor等抽象類,為訪問類文件中各元素定義了相應的visit方法,也按類文件的格式要求規定了調用次序。用戶只要制作子類,用自己的處理邏輯覆蓋相應方法,無須關注字節偏移量、常量池索引號等底層細節,就可實現從相關信息的檢測、獲取到運行代碼的生成、修改等各種功能。 典型的代碼結構如圖2所示,由若干ClassReader、ClassVisitor子類、ClasssWriter組成一處理鏈。
15、每個ClassVisitor子類通過對事件的過濾、變換、轉發,實現自己特定的功能。它可以原樣傳送事件,保持對應元素不變;也可以改變事件參數,導致相應元素的修改;或者忽略某一事件不作轉發,完成元素刪除;還可以引入新的事件,注入新增加的元素。復雜情況下也可將這些對象組成網狀結構,以完成多個類文件間的相互參照引用、合并、拆分等處理5。學生只需了解類文件結構,熟悉設計模式中的訪問者模式,這種修改、生成類文件的方法應是比較容易掌握的。 ClasssWriter cw=new ClassWriter(); ClassVisitor c1=new SubClassVisitor1(cw), c2=new S
16、ubClassVisitor2(c1); ClassReader cr=new ClassReader(類文件).accept(c2, 0); byte b=cw.toByteArray(); 圖2 處理代碼基本結構 3 熟悉Bytecode 用ASM直接生成類文件的工作是在JVM的底層展開的,應盡可能用于簡單處理。復雜的處理還是直接使用高級語言Java較為妥當,這樣就能進行良好的隔離、封裝,將它們組織成可組合使用的基本單元。在此基礎上再動態生成一些指令,按需訪問、調用它們,完成所希望的處理。這些指令需要按照某種特定邏輯在運行時添加、改變、刪除處理對象和運算步驟,如果直接生成還是感覺困難,依然
17、可以先用Java編寫一程序模版,確定處理的基本框架和各核心元素,運行時再以此為基礎在指令層面上進行簡單的增刪和替換。 除了簡單的類型或名字修改,以及數據或方法整體的增、刪、替換外,其他處理一般都牽涉到Bytecode代碼,因此有必要熟悉它們。JVM是一個堆棧型機器,所有的局部變量存儲和運算操作都在堆棧中實現,沒有寄存器,也不需要復雜的尋址方式,因此指令系統相對簡單,名義上它有200多條指令1,但經過歸納整理,實際只有不到50條不同指令(見表1),多種變化只是根據數據類型、判斷條件而有規則添加的前后綴,完全可以舉一反三,學習起來比真實的CPU如8086等要容易得多。指令大體可以分為三類。 堆棧操
18、作:用于為后續操作或方法調用,在棧頂配置需要的數據,或取得運算結果。它包括局部變量、對象/類數據成員、數組元素的進出棧,常量的進棧,棧頂元素的復制、交換等。 運算操作:指定需要完成的運算,包括算術和邏輯運算,類型轉換等,對于對象還有構造、判定等操作。 流程控制:用于改變執行流程,包括各種轉移指令、方法調用和返回指令。 這些指令恐怕是相關內容中最繁雜的部分,教學的關鍵是要讓學生理解JVM運行時的棧幀結構,指令也應著重介紹動態代碼生成時常用的部分,主要是各種方法調用,數據訪問,以及為此而必須進行的堆棧準備,表1中列出了堆棧和控制部分的相關指令。 表1 JVM指令系統 堆棧&各類變量入/出棧
19、&load、store、aload、astore、get、put&常量和棧頂處理&const_、bipush、sipush、ldc、pop、dup、swap&運算&算術運算&add、sub、mul、div、rem、neg、iinc、cmp&位或邏輯運算&shl、shr、ushr、and、or、xor&轉換、構造和判定&2、checkcast、new、newarray、instanceof、arraylength&控制&方法調用和其他&invoke、monitorenter、monitorex
20、it、nop&條件判斷&if、if_icmp、if_acmp、ifnull、ifnonnull&轉移和返回&goto、tableswitch、lookupswitch、return、athrow、jsr、ret&按數據類型&按成員屬性&按所需的堆棧要求&按創建的數組類型&按判斷條件&按操作要求&按數據寬度&在此處填入相應內容& 4 掌握類裝載機制 二進制類文件只有通過裝載機制裝入JVM才能發揮作用。通常情況下JVM只能根據classpath等預先指定的路徑搜索并載入已有文件。所以對于運行時動
21、態生成的二進制代碼,需要另行設法導入,才能正常使用。這就需要理解Java的類裝載機制。 Java類是在運行時按需動態裝載的。虛擬機中有多個類裝載器,負責獲取不同來源的類文件。除了啟動類裝載器(Bootstrap ClassLoader),其他都繼承自抽象類ClassLoader2。一般情況下,多個類加載器之間采用雙親委派模型組成一裝載器樹,以保證類代碼的惟一性。類文件從裝載到可以使用要經過載入、鏈接、初始化等階段4,載入階段獲取需要的二進制數據文件,鏈接階段包含了代碼合法性驗證、存儲空間獲取和可選的引用類解析等操作。 因此,要能在運行時載入動態生成的代碼,可以通過定義自己的類裝載器完成。作為父
22、類的ClassLoader有幾個關鍵方法: defineClass(String name, byte b, int off, int len):可以將一個正確的字節數組轉換為合法的Java類。 findClass(String name):按該裝載器特定的方法獲得需要的二進制數據,并將其轉換為Class對象。每個自定義裝載器都應該覆寫該方法,提供自己的載入機制。 loadClass(String name):用于裝載指定名字的類,它實現雙親委派模型,保證僅在必要時才調用自己的findClass方法完成裝載。通常不用改寫。 一般情況下自定義裝載器只需定義findClass方法,在其中利用ASM
23、的ClassWrite動態生成二進制代碼,再通過defineClass方法將它轉化為標準的Java類。其基本結構如圖3的上面部分所示。 ClassLoader myClassLoader=new ClassLoader() public Class<?> findClass(String name) byte classfile=用ASM的ClasssWriter的toByteArray()獲得的字節數組; return defineClass(name, classfile, 0, classfile.length); ; Class<?> c=myClassLoad
24、er.loadClass(name); - public static void premain(String agentArgs, Instrumentation inst) ClassFileTransformer transform=new ClassFileTransformer() public byte transform(ClassLoader loader, String classname, Class<?> clazz, ProtectionDomain domain, byte classfile) throws IllegalClassFormatExcep
25、tion if (當前處理的是需要變換的類代碼) byte newClassfile=用ASM對classfile變換后獲得的新數組; return newClassfile; else return null; ; inst.addTransformer(transform,false); 圖3 動態生成代碼的裝載 在不宜使用自定義類裝載器的場合,也可以用java.lang.instrument包2完成代碼的動態變換和生成。它有ClassFile- Transformer和Instrumentation兩個接口,ClassFileTransformer由用戶實現,完成代碼變換,它定義了transform方法,會在裝載器裝載了新類,對其進行合法性驗證之前執行。通過覆寫該方法,用戶可以攔截新載入的類,對其進行分類、檢測、增刪、修改,然后將變換后的新代碼交JVM執行。使用這個包時,用戶要提供一個包含premain方法的類。通過適當的命令,使系統在main方法執行之前執行該方法,用JVM提供的instrumentation對象添加用戶自定義的代碼變換方法,使所有新裝載的類都經過transform的處理,在實現了期望的變換后被JVM執行。圖3的下半部分演示了這種方案。 學
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 衛生計生監督協管培訓大綱
- 光伏電池產品培訓
- excel數據處理-第三部分統計圖表與公式函數
- 個人委托投資合同書
- 三人合伙創業合同
- 停車場建設合同
- 起重吊裝產品介紹培訓
- 維修工程承包合同書
- 房地產中介買賣合同
- 酒店裝修項目合同注意事項與規范
- 2025-2030中國汽車金融行業市場深度調研及發展策略與投資前景研究報告
- 2025年鐵路車輛鉗工(高級)職業技能鑒定參考試題庫(含答案)
- 跨越高原勇敢前行 課件 2025屆高考學習的高原期主題班會
- 2024年鄭州鐵路職業技術學院單招職業傾向性測試題庫必考題
- 企業水果禮盒采購合同樣本
- 移動業務代辦協議書
- 解除租賃合同的協議
- 2025年03月國家林業和草原局直屬單位公開招聘246人筆試歷年典型考題(歷年真題考點)解題思路附帶答案詳解
- 常德煙草機械有限責任公司招聘考試真題2024
- 2025屆天津市十二區重點學校高三下學期畢業聯考(一)英語試題(含答案)
- DB44-T 2623-2025 道路工程高韌超薄磨耗層技術規范
評論
0/150
提交評論