6

次のように、Byte Buddy を使用して、メソッドの呼び出しと Java 8 ラムダ式の呼び出しをインターセプトしようとしAgentBuilderます。

static {
  final Instrumentation inst = ByteBuddyAgent.install();
  new AgentBuilder.Default()
        .type(ElementMatchers.nameContainsIgnoreCase("foo"))
        .transform((builder, typeDescription) ->
                builder.method(ElementMatchers.any())
                        .intercept(MethodDelegation.to(LogInterceptor.class)))
        .installOn(inst);
}

public static class LogInterceptor {
  @RuntimeType
  public static Object log(@SuperCall Callable<?> superCall) throws Exception {
    System.out.println("yeah...");
    return superCall.call();
  }
}

Byte Buddy v0.7.1 を使用しています。

以下をインターセプトできますRunnable(匿名クラス)。

FunnyFramework.callMeLater(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from inner class");
    }
});

もちろん、通常の(非匿名) クラスとして定義されたオブジェクトへの呼び出しも含まれます。ただし、インターセプトは、次のようなラムダ式では機能しません。

FunnyFramework.callMeLater(() -> {
    System.out.println("Hello from lambda");
});

ラムダ式の呼び出しも傍受するにはどうすればよいですか? 私の知る限り、Byte Buddy にはLambdaInterceptorのようなものはありません。

4

1 に答える 1

7

Java 仮想マシンは、ラムダ式を表すクラス ファイルの変換を許可しません。ラムダ式を表すクラスは、別のクラスのセキュリティ コンテキストを継承する、いわゆる匿名クラス ローダー(従来の匿名クラスと混同しないでください) によって読み込まれます。たとえば、読み込まれたクラスを別のクラスにバインドする匿名クラス ローダーで読み込まれるクラスです。のメソッドにFooアクセスできます。この読み込みは、API を使用して明示的に行われます。privateFoosun.misc.Unsafe

Byte Buddy はJava インストルメンテーション APIにフックします。これにより、s のアプリケーションがsのロード プロセスClassFileTransformerにフックできるようになります。匿名クラス ローダーは常識では sと見なされないClassLoaderため、インストルメンテーション API はそのようなインストルメンテーションを許可しないため、ラムダ式のインストルメンテーションを禁止します。ClassLoader

もちろん、これはいくつかのユースケースでは残念なことですが、ほとんどの実際のアプリケーションでは、ラムダ式を計測するための実際の要件はありません。たとえば、実際のインストルメンテーションの多くは、特定のアノテーションでアノテーションが付けられたメソッドに適用されますが、これはラムダ式や関数型インターフェイスよりも複雑なクラスには適用できません。


UPDATE : Byte Buddy バージョン 1.1.0 では、ラムダ式を表すクラスをインストルメント化できます。このために、Byte Buddy は JVMLambdaMetafactoryを計測し、クラス生成をカスタム定義に置き換えます。この機能を有効にするには、ビルダーで次の手順を実行します。

new AgentBuilder.Default()
  .with(LambdaInstrumentationStrategy.ENABLED)

これは OpenJDK 8u40 でのみ機能することに注意してください。以前のバージョンでは、invokedynamic 呼び出しサイトに関連するバグがあり、これが機能しません。

于 2015-11-25T08:59:25.420 に答える