Javassist Basic
Javassist 是一個位元組碼檢測庫,允許你修改注入 Java 程式碼的位元組碼,Java 程式碼將由 Javassist 轉換為位元組碼,並在執行時新增到檢測的類/方法中。
讓我們編寫實際上採用假設類“com.my.to.be.instrumented.MyClass”的第一個轉換器,並將每個方法的指令新增到日誌呼叫中。
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public class DynamicTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
// into the transformer will arrive every class loaded so we filter
// to match only what we need
if (className.equals("com/my/to/be/instrumented/MyClass")) {
try {
// retrive default Javassist class pool
ClassPool cp = ClassPool.getDefault();
// get from the class pool our class with this qualified name
CtClass cc = cp.get("com.my.to.be.instrumented.MyClass");
// get all the methods of the retrieved class
CtMethod[] methods = cc.getDeclaredMethods()
for(CtMethod meth : methods) {
// The instrumentation code to be returned and injected
final StringBuffer buffer = new StringBuffer();
String name = meth.getName();
// just print into the buffer a log for example
buffer.append("System.out.println(\"Method " + name + " executed\" );");
meth.insertBefore(buffer.toString())
}
// create the byteclode of the class
byteCode = cc.toBytecode();
// remove the CtClass from the ClassPool
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return byteCode;
}
}
現在為了使用這個變換器(這樣我們的 JVM 將在載入時呼叫每個類的方法轉換),我們需要將這個工具新增到代理中:
import java.lang.instrument.Instrumentation;
public class EasyAgent {
public static void premain(String agentArgs, Instrumentation inst) {
// registers the transformer
inst.addTransformer(new DynamicTransformer());
}
}
開始我們的第一個儀器或實驗的最後一步是將該代理類實際註冊到 JVM 機器執行。實際執行此操作的最簡單方法是使用 shell 命令中的選項註冊它:
java -javaagent:myAgent.jar MyJavaApplication
正如我們所看到的,代理/變換器專案被新增為 jar,以執行任何名為 MyJavaApplication 的應用程式,該應用程式應包含名為“com.my.to.be.instrumented.MyClass”的類,以實際執行我們注入的程式碼。