1

Java Instrumentation は非常に興味深く、それについてもっと知りたいと思っているので、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();
}
}

「こんにちは」クラスは次のとおりです。

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!

「I modified it again!」という行がないことに気付くかもしれません。

どんな助けでも大歓迎です。

4

1 に答える 1