3

私はここで説明されているメソッド委譲をとても楽しんでいます:

http://www.javacodegeeks.com/2015/01/make-agents-not-frameworks.html

これはうまく機能します:

.intercept(MethodDelegation.to(LogInterceptor.class)
                              .andThen(SuperMethodCall.INSTANCE)

呼び出しをインターセプトし、メソッドに渡された引数を取得できます。これは、私が達成したいことの半分です。ただし、戻り値をキャプチャする同様に簡潔な方法は見つかりませんでした。呼び出しを実行するインターセプターに Callable を渡すことができることはわかっていますが、その道をたどると、スタックトレースが台無しになる確実な方法のように思えます。

「アラウンドメソッド」パターンを実装するには、簡単で標準的な方法があるはずです。

API for reals を掘り下げる前に: 何か足りないものはありますか?

4

1 に答える 1

2

いいえ、あなたは何も見逃していません。

Byte Buddy でコードを操作すると、この操作はアプリケーションのスタック トレースに反映されます。これは意図的なもので、何か問題が発生した場合のデバッグがはるかに簡単になります。ログ インターセプターが実行時例外をスローすることを考えてみてください。インターセプトが何らかの方法で元のメソッドにマージされた場合、他の開発者が理解するのは非常に混乱します。Byte Buddy のアプローチでは、インターセプターが実際にそこから利用できるため、原因となっているソースに簡単に移動できます。Byte Buddy を使用すると、生成されたコードから例外がスローされることはなく、問題をソース コードにまでさかのぼることができます。

また、スタック フレームをマージすると、呼び出し元に依存するコードに奇妙な副作用が生じる可能性があります。たとえば、セキュリティ マネージャーは、インターセプトされたコードよりもインターセプターに高いアクセス許可を与える場合があります。スタック フレームをマージすると、これらの権限が元に戻ります。

注入されたインターセプターを@Super Callable記述することは、アラウンドアドバイスを実装するための標準的な方法です。パフォーマンスについても心配する必要はありません。Byte Buddy は、スーパー メソッド呼び出しがオーバーヘッドなしで実行される可能性が最も高いように、JIT コンパイラが非常に簡単にコードをインライン化できるように記述されています。(それを示すベンチマークもあります。)あなたの例では、一般的なarround-adivceは次のようになります。

public class TimingInterceptor {

  @RuntimeType
  public static Object intercept(@Super Callable<?> zuper) 
      throws Exception {
    long before = System.currentTimeMillis();
    try {
      return zuper.call();
    } finally {
      System.out.println("Took: " + (Systen.currentTimeMillis() - before));
    }
  }
}

すべてのメソッドについて、実行にかかる時間がコンソールに出力されるようになりました。を使用してこのコードに委任しますMethodDelegation.to(TimingInterceptor.class)

@RuntimeType注釈を必ず使用してください。このように、Byte Buddy は実行時にキャストを試行し、この一般的な傍受を可能にします。

于 2015-11-17T07:04:24.140 に答える