2

私のプロジェクトでは、バイトコードを 2 段階で変換したいと考えています。順番が重要です。

  1. まず、メソッド定義を変更する必要があります
  2. 次に、メソッドが呼び出される方法

例えば

  1. 定義を からString hello()に変更String hello(String s)
  2. 通話を からHello.hello()に変更Hello.hello("newArgument")

最初のステップを実行するトランスを追加することができました。

public class MyJavaAgent {

    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst)
            throws Exception {
        instrumentation = inst;
        instrumentation.addTransformer(new MyClassFileTransformer());
    }
}

私の質問は: その方法で新しいトランスを追加できますか:

public class MyJavaAgent {

    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst)
            throws Exception {
        instrumentation = inst;
        instrumentation.addTransformer(new MyClassFileTransformer());
        instrumentation.addTransformer(new MyClassFileTransformer2());
    }
}

MyClassFileTransformerそして、前に彼の仕事をすることを確認してくださいMyClassFileTransformer2?

4

1 に答える 1

3

これをテストする簡単な方法があります... 各 Transformer クラスの変換メソッドに、それぞれのクラスに固有のメッセージを出力する System.out 命令を追加します。次に、コンソールで出力が取得される順序を確認します。Transformer2 よりも前に Transformer1 の一意のメッセージを取得した場合、はい、変換メソッドが順番に呼び出されます。

これは私がしたことです...

package Test;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class TransFormerTest  {


    public TransFormerTest() {
        super();
    }

    public static void premain(String agentArguments, Instrumentation instrumentation) {
        instrumentation.addTransformer(new Transformer1());
        instrumentation.addTransformer(new Transformer2());
    }
}

class Transformer1 implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        System.out.println(className + "one"); // one for Transformer
        return bytes;
    }
}

class Transformer2 implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        System.out.println(className + "two"); // two for Transformer 2
        return bytes;
    }
}

そのため、クラスがロードされ、トランスフォーマーが呼び出されるたびに、クラスの名前が 2 回表示されます。最初はサフィックスとして1 つ、次にサフィックスとして2 つです。

私は単純な Hello World プログラムでこの理論をテストしました...これが私の出力です::

Test/Transformer2 - one
sun/launcher/LauncherHelper - one
sun/launcher/LauncherHelper - two
java/lang/Enum - one
java/lang/Enum - two
HelloWorld - one
HelloWorld - two
java/lang/Void - one
java/lang/Void - two
Hello World
java/lang/Shutdown - one
java/lang/Shutdown - two
java/lang/Shutdown$Lock - one
java/lang/Shutdown$Lock - two

それで、秩序を維持しているように見えます。

そうは言っても、変換メソッドをチェーンすることを検討しましたか? 例えば...

public class TransFormerTest  {

    public TransFormerTest() {
        super();
    }

    public static void premain(String agentArguments, Instrumentation instrumentation) {
        instrumentation.addTransformer(new Transformer());
    }
}

class Transformer implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        byte[] bytes2 =  privateTransformer(className, bytes);
        return bytes2;
    }

    private byte[] privateTransformer(String className, byte[] bytes) {
        System.out.println(className + " - one");
            // TODO add code for First Transformation.
        byte[] bytes2 = privateTransformer2(className, bytes);
        return bytes2;
    }

    private byte[] privateTransformer2(String className, byte[] bytes) {
        System.out.println(className + " - two");
            // TODO add code for Second Transformation.
        return bytes;
    }
}

これでも同様の結果が得られ、変換が行われる可能性が高い順序が確実に維持されます。

于 2012-08-24T02:49:01.217 に答える