Ретрансформация приборов не работает

Я просто экспериментирую с Java Instrumentation, потому что это очень интересно, и я хотел бы узнать больше об этом. Я использую его в сочетании с библиотекой javassist, чтобы упростить манипулирование байт-кодом, и библиотеку "tools", которая включена в установку 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;
    }

}

}

Класс агента находится в другом фляге, это его базовая реализация:

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!

Вы можете заметить, что нет строки, которая гласит: "Я изменил это снова!"

Любая помощь приветствуется.

1 ответ

Не уверен, есть ли здесь какие-либо другие проблемы, но если вы хотите повторно преобразовать классы, вам нужно зарегистрировать ClassFileTransformer, используя метод, который позволяет вам указать, что преобразователь может выполнять повторное преобразование. т.е.

если вы называете приборостроение. addTransformer (ClassFileTraIsformer), то вы утверждаете, что преобразователь не поддерживает повторные преобразования.

Вам нужно вызвать приборостроение. addTransformer (ClassFileTraIsformer, true), и это заставит ваш трансформатор включиться.

Другие вопросы по тегам