深度探討Java字節代碼的操縱方法

Java做爲業界使用最爲廣泛的語言之一, 深得衆多軟件廠商和開發者的推崇, 可是關於Java語言的深度瞭解和運用, 本文爲IBM工程師成富編寫的《Java深度歷險》的第一部分Java字節代碼的操縱, 編寫Java源代碼, 再利用IDE提供的功能直接運轉Java順序就能夠了。 java), IDE會擔任調用Java的編譯器把Java源代碼編譯成平臺無關的字節代碼(bytecode), 以類文件的形式保存在磁盤上(. class)。 Java虛擬機(JVM)會擔任把Java字節代碼加載並執行。 Java通過這種方式來實現其「編寫一次, 四處運轉(Writeonce, runanywhere)」的目的。 JVM中的類加載器會擔任從包括字節代碼的字節數組(byte[])中定義出Java類。 可能會須要動態的生成Java字節代碼, 或是對已有的Java字節代碼中止修改。 這個時候就須要用到本文中將要介紹的相關技術。   動態編譯Java源文件  在普通狀況下, 開發人員都是在順序運轉以前就編寫完成了所有的Java源代碼而且成功編譯。 對有些使用來講, Java源代碼的內容在運轉時辰才幹肯定。 再由JVM來加載執行。 由系統在後臺編譯、運轉並中止判定。 使用的作法是直接在順序中調用Java編譯器。 可使用JDK中的工具類com. sun. Main, 不過該工具類只能編譯寄存在磁盤上的文件,   另一個可用的工具是EclipseJDTCore提供的編譯器。 這是EclipseJava開發環境使用的增量式Java編譯器, Play框架在內部使用了JDT的編譯器來動態編譯Java源代碼。 在開發模式下, 於是在修改代碼以後, 刷新頁面就能夠看到變化。 須要確保JDK中的tools. jar在使用的CLASSPATH中。 是關於如何在Java外面作四則運算, 好比求出來(3+4)7-10的值。 普通的作法是剖析輸出的運算表達式, 考慮到括號的存在和運算符的優先級等成果, 另一種作法是能夠用JSR223引入的腳本語言支持, 直接把輸出的表達式當作JavaScript或是JavaFX腳本來執行, 上面的代碼使用的作法是動態生成Java源代碼並編譯, 接着加載Java類來執行並獲取結果。 這種作法徹底使用Java來實現。   上面的代碼給出了使用動態生成的Java字節代碼的基本模式, 即通過類加載器來加載字節代碼, 創立Java類的對象的實例,   Java字節代碼增強  Java字節代碼增強指的是在Java字節代碼生成以後, 這種作法至關於對使用順序的二進制文件中止修改。 註解在Java源代碼中聲明瞭須要增強的行爲及相關的元數據, 用過JavaBeans的人可能對其中那些必需添加的getter/setter方法感到很繁瑣, 而通過字節代碼增強, 開發人員只須要聲明Bean中的屬性便可, getter/setter方法能夠通過修改字節代碼來自動添加。 用過JPA的人, 在調試順序的時候, 會發現實體類中被添加了一些額外的域和方法。 首先介紹一下表示一個Java類或接口的字節代碼的組織形式。   類文件  如上所示, 一個類或接口的字節代碼使用的是一種鬆懈的組織構造, 關於可能包括多個條目的內容, 如所實現的接口、域、方法和屬性等, 是以數組來表示的。 不一樣的內容類型, 關於開發人員來講, 直接操縱包括字節代碼的字節數組的話, 開發效率比擬低, 這些類庫包括ASM、cglib、serp和BCEL等。 好比考慮上面一個複雜的需求, 在一個Java類的全部方法執行以前輸出相應的日誌。 熟悉AOP的人都曉得, 相關的代碼以下:  從ClassWriter就能夠獲取到包括增強以後的字節代碼的字節數組, 增強部分的邏輯比擬複雜, 只是遍歷Java類中的全部方法並添加對System. println方法的調用。 在字節代碼中, 而要作的是生成調用System. 並把這些指令插入到指令集合的最前面。 ASM對這些指令作了抽象, ASM提供了一個工具類ASMifierClassVisitor, 當須要增強某個類的時候, 能夠先在源代碼上作出修改, 在JVM執行以前。 當獲取到Java類的字節代碼以後, 先中止增強處理,   因爲存在着少許對Java字節代碼中止修改的需求, lang. instrument包並在JDK6中失掉了進一步的增強。 這個類會包括一個premain方法。 JVM在啓動的時候會首先執行代理類的premain方法, 再執行Java順序自己的main方法。 在premain方法中就能夠對順序自己的字節代碼中止修改。 JDK6中還容許在JVM啓動以後動態添加代理。 java. instrument包支持兩種修改的場景, 一種是重定義一個Java類, 即徹底交流一個Java類的字節代碼;另一種是轉換已有的Java類, 至關於前面提到的類字節代碼增強。 首先須要實現java. lang. instrument. ClassFileTransformer接口來完成對已有Java類的轉換。   把該代理類打成一個jar包, 運轉Java順序的時候, 添加JVM啓動參數-javaagent:myagent. jar。 這樣的話, 完成相關的轉換操做。 能夠很容易的對二進制分發的Java順序中止修改, 十分適宜於性能剖析、調試跟蹤和日誌記載等義務。 另一個十分重要的做用是把開發人員從繁瑣的Java語法中解放出來。 開發人員應該只須要擔任編寫與業務邏輯相關的重要代碼。 關於那些只是因爲語法要求而添加的, 或是模式固定的代碼, 徹底能夠將其字節代碼動態生成出來。 字節代碼增強和源代碼生成是不一樣的概念。 源代碼生成以後, 就已經成爲了順序的一部分, 開發人員須要去維護它:要麼手工修改生成出來的源代碼, 要麼重重生成。 關於開發人員是徹底透明的。 妥善使用Java字節代碼的操縱技術, 能夠更好的解決某一類開發成果。java

相關文章
相關標籤/搜索