2

次のように実装された Java エージェントがあります。

public static void premain(String args, Instrumentation instrumentation) throws ClassNotFoundException {
    new AgentBuilder.Default()
      .type(isSubTypeOf(Object.class).and(nameStartsWith("com.my.domain")))
      .transform(new Transformer5())
      .installOn(instrumentation);
}

次にTransformクラス:

public class Transformer5 implements AgentBuilder.Transformer {
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader) {
        return builder.method(any().and(isDeclaredBy(typeDescription)))
                      .intercept(MethodDelegation.to(Interc4.class));
    }
}

そしてインターセプター:

public class Interc4 {

    static String indent = "";

    @RuntimeType
    @BindingPriority(BindingPriority.DEFAULT * 3)
    public static Object intercept(@SuperCall Callable<?> zuper, 
                                   @AllArguments Object[] allArguments, 
                                   @Origin String method) throws Exception {

        System.out.println(indent + "Intercepted4 M" + method);

        try {
            indent += "  ";
            return zuper.call();
        } finally {
            //post process
            indent = indent.substring(0, indent.length()-2);
        }

    }

}

これの問題は、コンストラクターをインターセプトせず、この種のエラーも発生することです

インターフェイス型の非パブリックまたは非仮想メソッド 'lambda$static$1' を定義できません

あるドメインからクラス内の各メソッドをプロキシするインターセプターを作成する最良の方法は何ですか (メソッド名を取得し、メソッド引数 (存在する場合) を検査し、実行を転送できるようにしたい)。

4

1 に答える 1

3

何が起こっているのかには2つの理由があります。

  1. Cannot define non-public or non-virtual method 'lambda$static$1' for interface typeByte Buddy の検証バグが原因です。次のリリースでこれを修正する予定です。それまでの間、検証を無効にすることができますnew AgentBuilder.Default(new ByteBuddy().with(TypeValidation.DISABLED))

  2. を介してマッチングすることにより、メソッドを明示的にインターセプトするだけ.method( ... )です。.constructor( ... )コンストラクターは、または呼び出し可能オブジェクトによってインターセプトできます.invokable( ... )。ただし、スーパー メソッド呼び出しをハードコーディングする必要があるコンストラクターにインターセプターを使用することはできません。ただし、インターセプターを 2 つのビットに分割できます。

    class Interceptor {
      public static void before() { ... }
      public static void after() { ... }
    }
    

    使用して

    .intercept(MethodDelegation.to(Interceptor.class).filter(named("before")
       .andThen(SuperMethodCall.INSTANCE
       .andThen(MethodDelegation.to(Interceptor.class).filter(named("after"))))
    

このようにして、Byte Buddy はスーパー コンストラクターの呼び出しをハードコーディングし、メソッドbeforeafterメソッドをトリガーすることができます。@Thisメソッドではアノテーションを使用できないことに注意してくださいbefore

于 2016-07-24T23:23:12.730 に答える