この記事では、Java 動的プロキシの InvocationHandler について簡単に紹介します。必要な方は参考にしていただければ幸いです。
Java の動的プロキシ、Proxy、および InvocationHandler の概念については、インターネット上に非常に詳細な記事があります。実際、これらの概念はそれほど複雑ではありません。ここで、最も単純な例を通じて InvocationHandler が何であるかを理解しました。 InvocationHandler は Spring フレームワークの実装で広く使用されていることに言及する価値があります。つまり、InvocationHandler を徹底的に理解すれば、将来の Spring ソース コード学習のための強固な基盤を築くことができます。
指定した人に「こんにちは」または「さようなら」を挨拶できる 2 つのメソッドを含むインターフェイスを開発します。
public interface IHello { void sayHello(String name); void sayGoogBye(String name); }
この IHello インターフェイスを実装する単純なクラスを作成します。
public class Helloimplements implements IHello { @Override public void sayHello(String name) { System.out.println("Hello " + name); } @Override public void sayGoogBye(String name) { System.out.println(name+" GoodBye!"); } }
この実装クラスの使用は、今のところ特別なことではありません。
ここで、次の要件を受け取ったとします。上司は、実装クラスが誰かに挨拶するたびに、挨拶の詳細をログ ファイルに記録する必要があると要求しています。わかりやすくするために、挨拶の前に次のステートメント行を出力して、ロギング アクションをシミュレートします。
System.out.println("问候之前的日志记录...");
これは簡単ではないと思われるかもしれません? Helloimplements の対応するメソッドを直接変更し、ログのこの行を対応するメソッドに挿入します。
ただし、上司の要求は、元の Helloimplements クラスの変更を許可しないことです。実際のシナリオでは、Helloimplements はサードパーティの jar パッケージによって提供される場合があり、コードを変更する方法はありません。
デザイン パターンでプロキシ パターンを使用できる、つまり、新しい Java クラスをプロキシ クラスとして作成できる、と言えるかもしれません。また、IHello インターフェイスを実装し、Helloimplements クラスのインスタンスをプロキシ クラスに渡します。 Helloimplements のコードを変更する必要はありませんが、プロキシ クラスにロギング コードを記述することができます。完全なコードは次のとおりです。
public class StaticProxy implements IHello { private IHello iHello; public void setImpl(IHello impl){ this.iHello = impl; } @Override public void sayHello(String name) { System.out.println("问候之前的日志记录..."); iHello.sayHello(name); } @Override public void sayGoogBye(String name) { System.out.println("问候之前的日志记录..."); iHello.sayGoogBye(name); } static public void main(String[] arg) { Helloimplements hello = new Helloimplements(); StaticProxy proxy = new StaticProxy(); proxy.setImpl(hello); proxy.sayHello("Jerry"); } }
このアプローチにより、要件を達成できます。
InvocationHandler を使用して次のことを行う方法を見てみましょう。同じ効果が得られます。
InvocationHandler是一个JDK提供的标准接口。看下面的代码: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynaProxyHello implements InvocationHandler { private Object delegate; public Object bind(Object delegate) { this.delegate = delegate; return Proxy.newProxyInstance( this.delegate.getClass().getClassLoader(), this.delegate .getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { System.out.println("问候之前的日志记录..."); // JVM通过这条语句执行原来的方法(反射机制) result = method.invoke(this.delegate, args); } catch (Exception e) { e.printStackTrace(); } return result; }
上記のコードのバインド メソッドは、以前のプロキシ クラス StaticProxy の setImpl メソッドに非常に似ていますが、このバインド メソッドの入力パラメータのタイプはより汎用的です。ロギングコードはメソッド呼び出しに記述されます。
使用方法を参照してください:
static public void main(String[] arg) { DynaProxyHello helloproxy = new DynaProxyHello(); Helloimplements hello = new Helloimplements(); IHello ihello = (IHello) helloproxy.bind(hello); ihello.sayHello("Jerry"); }
実行効果は、StaticProxy ソリューションの場合とまったく同じです。
最初にデバッグしましょう。バインド メソッドが実行されると、メソッド Proxy.newProxyInstance が呼び出され、Helloimplements クラスのインスタンスが渡されます。
デバッガーでステートメント IHello ihello = (IHello) helloproxy.bind(hello) によって返される ihello 変数を確認します。その静的型は IHello ですが、デバッガでその実際の型を観察すると、これは Helloimplements のインスタンスではなく、invoke メソッドで手書きしたログ行を含め、JVM が処理したものであることに注意してください。コード。 ihello タイプは $Proxy0 です。
JVM によって処理されるこの変数の SayHello メソッドが呼び出されると、JVM は呼び出しを DynaProxyHello.invoke に自動的に転送します。
したがって、invoke メソッドでは、手書きのログ コードが実行され、次に元の SayHello コードが Java リフレクションを通じて実行されます。
友人の中には、InvocationHandler は静的プロキシ StaticProxy よりも複雑ではないかと尋ねる人もいるかもしれません。メリットは何ですか?
上司のニーズが再び変化し、挨拶と別れの挨拶の方法で異なるロギング戦略を使用する必要があると仮定します。
InvocationHandler を使用してエレガントに実装する方法を見てみましょう:
この例で Java の動的機能を皆さんに理解していただければ幸いです。プロキシ InvocationHandler の最も基本的な理解を取得します。
以上がJava ダイナミック プロキシの InvocationHandler の簡単な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。