Java 動態程式碼變更 (一)

在 JDK 5.0 的 API 中新增了 java.lang.instrument 套件,這個套件的主要用途是提供外部 bytecode instrument 工具與 Java Runtime 的連接點,讓外部工具可以在類別載入時或執行期動態改變類別實作。

比較著名的 open source bytecode instrument 工具包括 javassistASM 與 BCEL 等。

動態改變類別的實作用途很廣,可以用 Bytecode instrument 製作 Intercepter,也可以幫類別新增 Method。

在 JDK 5.0 之前,也可以由 Bytecode instrument 工具達成類似的功能,但必須透過自訂的 class loader 或 factory method 載入或修改類別,

這樣比起直接與載入程序結合的方式效率來的差,且 programming effort 也較大。

在 Java 5.0 實作 class load-time bytecode instrument 的方式是先建立一個 bytecode transformer agent ,

這個 agent 是一個 jar 檔,透過 manifest 的方式來安裝 agent 類別。

實作的步驟如下:

  1. 實作 ClassFileTransformer 介面
  2. 透過類別宣告 public static void premain(String agentArguments, Instrumentation instrumentation) 方法,掛載自訂的 ClassFileTransformer 類別
  3. 建立 manifest 檔,宣告 Premain-Class 類別,並將步驟 1~3 壓成自訂  jar 檔
  4. 執行 java -javaagent:自訂 jar 檔.jar=自訂參數 要執行的類別

以下舉一實例:

步驟1:

public class TestTransformer implements ClassFileTransformer{

public byte[] transform(ClassLoader loader,

String className,

Class<?> classBeingRedefined,

ProtectionDomain protectionDomain,

byte[] bytes) throws IllegalClassFormatException {

System.out.println(“Transformer to Transform Class: " + className);

try {

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.makeClass(new ByteArrayInputStream(bytes));

CtMethod m = cc.getDeclaredMethod(“main");

m.insertBefore(“{ System.out.println(“Before invoke main"); }");

m.insertAfter(“{ System.out.println(“After invoke main"); }");

return cc.toBytecode();

} catch (Exception e) {

System.out.println(“Ignore class " + className);

}
return bytes;

}

}

步驟2:

public class TestPreMain{

public static void premain(String agentArguments, Instrumentation instrumentation){

System.out.println(“agentArguments="+agentArguments);

instrumentation.addTransformer( new TestTransformer() ) ;

}

}

步驟3:

[File: manifest.mf]
Premain-Class: TestPreMain

執行 jar -cvfm TestAgent.jar manifest.mf  TestTransformer.class TestPreMain.class

步驟4:

執行  java -javaagent:TestAgent.jar=XXX  HelloWorld

執行結果:

agentArguments=XXX
Transformer to Transform Class: TestMain
Before invoke main
Hello World!
After invoke main

廣告
張貼於Java

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

四月 2011
« 三月   五月 »
 123
45678910
11121314151617
18192021222324
252627282930  
分類
Follow crluo0929 on WordPress.com
部落格統計
  • 30,453 hits
文章存檔
%d 位部落客按了讚: