web-dev-qa-db-ja.com

標準のJava機能(AspectJなどなし)でメソッド呼び出しをインターセプトするにはどうすればよいですか?

いくつかのsetter呼び出しに反応できるように、いくつかのクラスMyClassへのすべてのメソッド呼び出しをインターセプトしたいと思います。

動的プロキシを使用しようとしましたが、私が知る限り、これは一部のインターフェイスを実装するクラスでのみ機能します。しかし、MyClassにはそのようなインターフェースはありません。

ラッパークラスを実装する以外に、すべての呼び出しをメンバーに委任する方法はありますか?これは、MyClassのインスタンスであるか、AOPを使用する以外にありますか?

19
Tobias Hilka

お気づきのとおり、JDK動的プロキシ(インターフェースなし)は使用できませんが、 Spring およびCGLIB(Springに含まれるJAR)を使用すると、次のことができます。

public class Foo
{
    public void setBar()
    {
        throw new UnsupportedOperationException("should not go here");
    }

    public void redirected()
    {
        System.out.println("Yiha");
    }
}

Foo foo = new Foo();
ProxyFactory pf = new ProxyFactory(foo);

pf.addAdvice(new MethodInterceptor()
{
    public Object invoke(MethodInvocation mi) throws Throwable
    {
        if (mi.getMethod().getName().startsWith("set"))
        {
            Method redirect = mi.getThis().getClass().getMethod("redirected");
            redirect.invoke(mi.getThis());
        }
        return null;
    }
});

Foo proxy = (Foo) pf.getProxy();
proxy.setBar(); // prints "Yiha"
26
eljenso

あなたが本当に醜いことをする準備ができているなら、見てください:

http://docs.Oracle.com/javase/7/docs/technotes/guides/jpda/

基本的に、デバッガーインターフェイスでは、デバッガーのようにアタッチできるため、呼び出しをインターセプトできます。これは本当に悪い考えだと思いますが、それが可能かどうか尋ねられたことを覚えておいてください。

13
Nick Fortescue

この目的のために小さなフレームワークを開発しました。次の場所で確認できます: http://code.google.com/p/Java-interceptor/ (svnを使用して確認してください)。

2
Pierantonio

Javaには、メソッドインターセプト用の実際の言語機能はありません(静的言語にはありません)。

デバッガーインターフェイスを使用するというニックのアイデアが好きです。それはただの意味です。

必要な簡単な答えは次のとおりです。プロキシまたはラッパーを使用してクラスを実際に置き換えることなく、Javaでメソッド呼び出しをインターセプトする方法はありません。

注:AOPライブラリは、これを自動的に実行します。

2
Gareth Davis

Javaの達人の一部はこれに眉をひそめるかもしれませんが、プリミティブ型とセッターを完全に回避することである程度の成功を収めました。私のクラスは次のようになります。

class Employee extends SmartPojo {
    public SmartString name;
    public SmartInt age;
}

2つのことに気付くでしょう:1。すべてが公開されています。 2.コンストラクターはありません。

魔法は、「スマート」インターフェースを実装するフィールドを検索して初期化するSmartPojoで発生します。これはプリミティブではない(そして最終クラスではない)ので、set()メソッドとget()メソッドを追加できますモデル内のすべてのフィールドに対して1か所で。そのため、セッター/ゲッターが無駄になることはもうありません。通知を(1か所に)追加するのは驚くほど簡単です。

確かに、これはもはやPOJOではなく、ほとんどの点でBeanではありませんが、これらの古いアイデアは、役立つ以上に私を制限していることがわかりました。 YMMV。

1
Aaron Digulla

AspectJには多くの魔法はありません。あなたはあなた自身のエージェントを書くことができます。 http://Java.Sun.com/javase/6/docs/api/Java/lang/instrument/package-summary.html は良い出発点のようです。

0
  1. クラスがインターフェースを実装できないのはなぜですか?インターセプトするすべてのメソッドを含むインターフェイスをそこから抽出して、動的プロキシメカニズムを簡単に使用できます。クラスではなくインターフェイスを使用してコーディングすることも、優れたプログラミング手法です。

  2. Spring AOP機能(内部で動的プロキシを使用している)を備えたSpringフレームワークを使用してそれを行うことができます。クラスを構成ファイルでSpringBeanとして定義する必要があり、クラスのクライアントは、Springアプリケーションコンテキストからインスタンスを取得するか、依存関係として自動的に取得する必要があります(たとえば、setMyClass(MyClass mc)メソッドを定義することにより) )。そこから、このクラスへのすべてのメソッド呼び出しをインターセプトするアスペクトの定義に簡単に進むことができます。

0
Stas