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”的类,以实际执行我们注入的代码。