ホームページ >Java >&#&チュートリアル >Java での動的プロキシの実装に関するチュートリアル
以下の内容は一部インターネット上の内容を元にしています。原作者様に感謝の意を表します。
Java での動的プロキシの実装の鍵は、Proxy と InvocationHandler の 2 つです。InvocationHandler インターフェイスの invoke メソッドから始めて、Java が動的プロキシを実装する方法を簡単に説明します。まず、Invoke メソッドの整合性は次のとおりです。 java コード
method.invoke(obj, args);
returnプロキシ インターフェイスの 1 つを介したプロキシ インスタンスのメソッド呼び出しは、次のようになります。プロキシ インスタンス、呼び出されたメソッドを識別する java.lang.reflect.Method オブジェクト、および引数を含む Object 型の配列を渡して、インスタンスの呼び出しハンドラーの invoke メソッドにディスパッチされます。 by このことから、上記の推測が正しいことがわかり、プロキシ パラメータがプロキシ クラスのインスタンスに渡されていることもわかります。
public インターフェース Subject {
//実際の役割: Subject の request() メソッドを実装しました public class RealSubject implements Subject{ パブリック void request(){ System.out.println("実際の主題から。"); } } Java コード { プライベート オブジェクト obj;//これは動的プロキシの利点です。カプセル化されたオブジェクトはオブジェクト型であり、あらゆる種類のオブジェクトを受け入れます。 public DynamicSubject(オブジェクトオブジェクト) } // このメソッドは私たちが作ったものではありません を明示的に呼び出しますpublic Object invoke(オブジェクトプロキシ, メソッドメソッド, Object[] args) "" + メソッドを呼び出す前); System.out.println("呼び出し後" + メソッド); ) //クライアント: プロキシインスタンスを生成し、 request() メソッドを呼び出しました public class Client { public static void main(String [ ] args) throws Throwable{ Subject rs=new RealSubject();//ここにプロキシを指定します Class インターフェース()、ds); /ここでは、サブジェクトが Proxy のインスタンスであることを実行結果を通じて証明できます。 System.out .println(subject instanceof Proxy); toString()); "件名の属性は次のとおりです: "); () .getDeclaredFields(); System.out.print("n"+" 件名のメソッドは次のとおりです: ") ().getDeclaredMethods( ); "n"+"サブジェクトの親クラスは: "+subject.getClass().getSuperclass()); } System.out.println("nn"+"演算結果は次のとおりです: "); subjectのClassクラスは次のとおりです: class $Proxy0 subjectの属性: m1、m3、m0、m2、 public static Object newProxyInstance(ClassLoader loader, スロー IllegalArgumentException if (h == null) { throw new NullPointerException(); /* * 指定されたプロキシを検索または生成しますクラス。 */ /* * 指定された 呼び出しハンドラーを使用して その コンストラクター を呼び出します。 */ お試しください { /* * プロキシソースコード始まりにはこの定義があります: * private final static Class [] constructorParams = { InvocationHandler.class }; * 短所は、InvocationHandler 型に参加する構築メソッド */ return (Object) cons.newInstance(new Object[] { h }); catch (NoSuchMethodException e) { throw new InternalError(e.toString()); catch (IllegalAccessException e) { throw new InternalError(e.toString()); catch (InstantiationException e) { throw new InternalError(e.toString()); catch (InvocationTargetException e) { throw new InternalError(e.toString()); } Proxy を継承する $Proxy0 のソース コードを見てみましょう。 Javaコード public final class $Proxy0 extends Proxy implements Subject { private static Method m1; private static メソッド m0; private static メソッド m3; private static メソッド m2; 静的 { 試してみる { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", 新しい クラス[0]); m3 = Class.forName("***.RealSubject").getMethod("request", 新しい クラス[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", 新しい クラス[0]); } catch (NoSuchMethodException no suchmethodException) { throw new NoSuchMethodError(no suchmethodException.getMessage()); } catch (ClassNotFoundException classnotfoundException) { throw new NoClassDefFoundError(classnotfoundException.getMessage() ); } } //static public $Proxy0(InvocationHand) ler invocationhandler) { super(invocationhandler); } @Override public final boolean equals(Object obj) { 試してください { return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); } catch (Throwable スロー可能) { throw new UndeclaredThrowableException(throwable); } } @オーバーライド public final int hashCode() { try { return ((Integer) super.h.invoke(this, m0, null)).intValue(); } catch (Throwable スロー可能) { throw new UndeclaredThrowableException(throwable); } } public final void request() { 試してください { super.h。 invoke(this, m3, null); 戻る; } catch (エラーe) { } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } @オーバーライド public final String toString() { try { return (String) super.h.invoke(this, m2, null); } catch (Throwable スロー可能) { throw new UndeclaredThrowableException(throwable); } } }
Javaコード
//実装された InvocationHandler
サブジェクト内のメソッド: request 、 hashCode、equals、toString、subject の親クラス: class java.lang.reflect.Proxy
Proxy.newProxyInstance(ClassLoaderloader,Class>[]interfaces,InvocationHandler h) は以下のことを行います。
(1) パラメータローダーとインターフェイスの呼び出しメソッドに従ってgetProxyClass(loader,interfaces) は、プロキシ クラス $Proxy0 を作成します。$Proxy0 クラスは、interfaces インターフェイスを実装し、Proxy クラスを継承します (2) $Proxy0 をインスタンス化し、コンストラクターで DynamicSubject を渡し、$Proxy0 コンストラクターを呼び出します。親クラスの Proxy は、次のように h に値を割り当てます。
クラス プロキシ{
InvocationHandler h=null; protected Proxy(InvocationHandler h) { ...
次に、取得した $Proxy0 インスタンスを Subject にキャストし、subject への参照を割り当てます。 subject.request() メソッドが実行されると、$Proxy0 クラスの request() メソッドが呼び出され、次に親クラス Proxy の h の invoke() メソッド、つまり InvocationHandler.invoke() が呼び出されます。
追記: 1. 説明する必要があるのは、Proxy クラスの getProxyClass メソッドが Proxy Class クラスを返すということです。なぜこんなことを説明したかというと、最初に私が返ってきたものを「代理クラスのクラス」だと思ってしまうというレベルの低い間違いを犯したからです――! getProxyClass のソース コードを確認することをお勧めします。これは非常に長いです。 =
2. $Proxy0 のソース コードから、動的プロキシ クラスは、明示的に定義されたインターフェイス内のメソッドをプロキシするだけでなく、Java ルート クラス オブジェクト内の継承されたquals() および hashcode() もプロキシすることがわかります。 . 、toString()、およびこれら 3 つのメソッドのみです。
Q: これまでのところ、invoke メソッドの最初のパラメータは Proxy のインスタンス (正確には $Proxy0 のインスタンスが使用されます) ですが、その用途は何ですか?言い換えれば、プログラムはどのように効果を発揮するのでしょうか?
A: 私の現在のレベルでは、このプロキシ パラメーターは動的プロキシ メカニズム全体で効果がありません。InvocationHandler の呼び出しメソッドのプロキシ パラメーターは使用されません。渡されるパラメータは、実際にはプロキシ クラスのインスタンスです。おそらくプログラマが invoke メソッドでリフレクションを使用してプロキシ クラスに関する情報を取得できるようにするためだと思います。
以上がJava での動的プロキシの実装に関するチュートリアルの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。