[英]Problems with Java Agent for Bytecode Instrumentation
這是我第一次實現Java代理,並嘗試學習有關字節碼檢測的知識。 閱讀了幾篇介紹和教程后,我編寫了一個帶有兩個類(夏季和應用程序)的小型應用程序。 現在我想通過premain方法運行一個Java代理以使用以下代碼顯示執行路徑:
public class TestJavaAgent {
public static void premain(String agentArgument,
Instrumentation instrumentation){
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
ClassPool cp = ClassPool.getDefault();
try {
CtClass cc = cp.get("Summer");
CtMethod methods [] = cc.getMethods();
for( CtMethod method : methods){
System.out.println("Entering "+method.getName());
method.addLocalVariable("elapsedTime", CtClass.longType);
method.insertBefore("elapsedTime = System.currentTimeMillis();");
method.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
+ "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
}
return cc.toBytecode();
} catch (Exception ex) {
return bytes;
}
}
});
}
}
我通過java -javaagent{Agent JAR} -jar {Application Jar}
啟動了代理,但是它沒有顯示任何插入的消息。 調試代碼后,我意識到“ ClassPool.getDefault()”之后的所有內容都無法實現,但我不知道為什么。 有人能幫我嗎?
轉換器應該轉換作為參數傳遞的類,而不是您喜歡的任意類。 注冊后,將為所有已加載的類(包括您自己使用的類)(第一個是ClassPool
)調用此ClassPool
。 因此,您正在創建循環依賴項。
您必須檢查類名參數,然后等待直到要轉換的類的方法被調用為止。 對於所有其他類,只需返回null
。
public class TestJavaAgent {
public static void premain(String agentArgument, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader classLoader,
String className, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
if(!className.equals("Summer")) return null;
ClassPool cp = ClassPool.getDefault();
try {
// use the class bytes your received as parameter
cp.insertClassPath(new ByteArrayClassPath(className, bytes));
CtClass cc = cp.get("Summer");
CtMethod[] methods = cc.getMethods();
for( CtMethod method : methods){
System.out.println("Entering "+method.getName());
method.addLocalVariable("elapsedTime", CtClass.longType);
method.insertBefore("elapsedTime = System.currentTimeMillis();");
method.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
+ "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
}
return cc.toBytecode();
} catch (Exception ex) {
return null;
}
}
});
}
}
請注意,如果您不進行任何更改,則返回null
勝於返回原始數組,因為JVM可以立即識別出您沒有進行任何更改,而無需查看數組內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.