我只是在尝试Java Instrumentation,因为它非常有趣,我想了解更多。我正在将它与javassist库结合使用,使字节码操作变得更加容易,并且JDK中包含的“工具”库也会安装。
这是我的主要课程:
public class MainClass {
public static boolean first = true;
static{
AgentClass.initialize();
}
public static void loadAgent(){
String path = System.getProperty("user.dir") + "\\AgentJar.jar";
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
int p = nameOfRunningVM.indexOf('@');
String pid = nameOfRunningVM.substring(0, p);
try {
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(path, "");
vm.detach();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args){
System.out.println("First run-through, code should be modified once.");
new Hello().hello();
first = false;
try {
AgentClass.getInstrumentation().retransformClasses(Class.forName("test.Hello"));
} catch (Exception e){
e.printStackTrace();
}
System.out.println("Second run-through, code should be modified twice.");
new Hello().hello();
}
}
以下是“Hello”类:
public class Hello {
public void hello(){
System.out.println("Hello World!");
}
}
这是FileTransformer类:
public class FileTransformer implements ClassFileTransformer{
private static boolean first = true;
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.contains("Hello"))
return null;
else{
byte[] result;
CtClass cc = null;
try {
cc = ClassPool.getDefault().get("test.Hello");
CtMethod method = cc.getDeclaredMethod("hello");
if (MainClass.first){
System.out.println("In transformer: first");
method.insertAfter("System.out.println(\"Modified First Time!\");");
}else{
System.out.println("In transformer: second");
method.insertAfter("System.out.println(\"I modified it again.!\");");
}
cc.writeFile();
result = cc.toBytecode();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return result;
}
}
}
代理类在另一个jar中,它是它的基本实现:
public class AgentClass {
protected static Instrumentation inst;
private static boolean added = false;
public static void agentmain(String args, Instrumentation inst){
AgentClass.inst = inst;
if (!added)
inst.addTransformer(new FileTransformer());
}
public static void premain(String args, Instrumentation inst){
AgentClass.inst = inst;
inst.addTransformer(new FileTransformer());
added = true;
}
public static void initialize(){
if (inst == null){
MainClass.loadAgent();
}
}
public static Instrumentation getInstrumentation(){
return inst;
}
}
当我跑步时,我没有遇到任何错误。但是,输出并不是我所期望的。
以下是我得到的输出:
First run-through, code should be modified once.
In transformer: first
Hello World!
Modified First Time!
Second run-through, code should be modified twice.
Hello World!
Modified First Time!
你可能会注意到没有一行显示“我再次修改它!”
感谢任何帮助。
答案 0 :(得分:0)
不确定此处是否存在任何其他问题,但是如果要重新转换类,则需要使用允许您指定转换器可以重新转换的方法来注册ClassFileTransformer。即。
如果你拨打了仪器。addTransformer(ClassFileTraIsformer),那么你就说明变压器不支持重新传输。
您需要调用检测。addTransformer(ClassFileTraIsformer, true)这将使您的变压器启动。