ホームページ >Java >&#&チュートリアル >Java での動的プロキシの実装に関するチュートリアル

Java での動的プロキシの実装に関するチュートリアル

零下一度
零下一度オリジナル
2017-06-30 09:52:451334ブラウズ

以下の内容は一部インターネット上の内容を元にしています。原作者様に感謝の意を表します。

Java での動的プロキシの実装の鍵は、Proxy と InvocationHandler の 2 つです。InvocationHandler インターフェイスの invoke メソッドから始めて、Java が動的プロキシを実装する方法を簡単に説明します。まず、Invoke メソッドの整合性は次のとおりです。 java コード

Public Object Invoke (Object Proxy, Method Method, Object [] ARGS)
Throws Throwable
Java での動的プロキシの実装に関するチュートリアル
{
  1. method.invoke(obj, args);

    return
  2. null;まず、Method が呼び出しメソッド、つまり実行する必要があるメソッドであると推測します。メソッドのパラメータ、プロキシ、このパラメータは何ですか?上記の invoke() メソッドの実装は比較的標準的な形式であり、ここでは proxy パラメーターが使用されていないことがわかります。次のように、JDK ドキュメントでプロキシの説明を参照してください。
  3. Java コード
  4. プロキシ インターフェイスの 1 つを介したプロキシ インスタンスのメソッド呼び出しは、次のようになります。プロキシ インスタンス、呼び出されたメソッドを識別する java.lang.reflect.Method オブジェクト、および引数を含む Object 型の配列を渡して、インスタンスの呼び出しハンドラーの invoke メソッドにディスパッチされます。 by このことから、上記の推測が正しいことがわかり、プロキシ パラメータがプロキシ クラスのインスタンスに渡されていることもわかります。

  5. 説明の便宜上、動的プロキシを実装する簡単な例を以下に示します。

public インターフェース Subject {

public
void request();
Java での動的プロキシの実装に関するチュートリアル




Javaコード

  1. //実際の役割: Subject の request() メソッドを実装しました

  2. public class RealSubject implements Subject{

  3. パブリック void request(){

  4. System.out.println("実際の主題から。");

  5. }

  6. }

Java コード
//実装された InvocationHandler

public Java での動的プロキシの実装に関するチュートリアルclass DynamicSubject implements In vocationHandler
  1. {

  2. プライベート オブジェクト obj;//これは動的プロキシの利点です。カプセル化されたオブジェクトはオブジェクト型であり、あらゆる種類のオブジェクトを受け入れます。 public DynamicSubject(オブジェクトオブジェクト)

    {
  3. this.obj = ob j;
  4. }

  5. // このメソッドは私たちが作ったものではありません

  6. を明示的に呼び出しますpublic Object invoke(オブジェクトプロキシ, メソッドメソッド, Object[] args)

    throws Throwable
  7. {

  8. System.out.println(

    "" + メソッドを呼び出す前);

    Method.invoke(obj, args); //-----> このステップの詳細については、次の記事を参照してください。各クラスのメソッドを読むと理解できます。 。
  9. System.out.println("呼び出し後" + メソッド);

  10. )

    1. //クライアント: プロキシインスタンスを生成し、 request() メソッドを呼び出しました

    2. public class Client {

    3. public static void main(String [ ] args) throws Throwable{

    4. Subject rs=new RealSubject();//ここにプロキシを指定します Class

    5. InvocationHandler ds=
    6. new DynamicSubject(rs); class<>

      インターフェース()、ds); /ここでは、サブジェクトが Proxy のインスタンスであることを実行結果を通じて証明できます。

    7. System.out .println(subject in​​stanceof Proxy);

    8. //ここで、この $Proxy0 クラスが Proxy を継承し、Subject インターフェースを実装していることがわかります。
    9. toString());

    10. System.out.print(

      "件名の属性は次のとおりです: "); () .getDeclaredFields();

    11. System.out.print("n"+" 件名のメソッドは次のとおりです: ") ().getDeclaredMethods( );

    12. System.out.println(

      "n"+"サブジェクトの親クラスは: "+subject.getClass().getSuperclass());

    13. システム。インターフェース=subject.getClass().getInterfaces();
    14. }

    15. System.out.println("nn"+"演算結果は次のとおりです: ");

    16. )
    17. 実行結果は次のとおりです: ここではパッケージ名は省略しています。 * **
    18. tru​​eの代わりに

subjectのClassクラスは次のとおりです: class $Proxy0 subjectの属性: m1、m3、m0、m2、
サブジェクト内のメソッド: request 、 hashCode、equals、toString、
subject の親クラス: class java.lang.reflect.Proxy

subject 実装インターフェイス: cn.edu.ustc.dynamicproxy.Subject、
Java での動的プロキシの実装に関するチュートリアル
実行結果は次のとおりです: public abstract void ***.Subject.request() を呼び出す前に
  1. From real subject.
  2. public abstract void ***.Subject.re Quest( ) を呼び出した後
  3. PS: この結果の情報は、少なくとも私にとっては非常に重要です。 。動的プロキシに関する私の混乱の根本的な原因は、私が上記の subject.request() を誤解していたことにあるため、少なくとも、前回の呼び出しで絡まったサブジェクトとプロキシの関係がわかりませんでした。 request() の は invoke() と接続されていますが、invoke はどのようにしてリクエストの存在を認識するのでしょうか。実際、上記の true とクラス $Proxy0 は、以下に示す $Proxy0 のソース コードと合わせて、動的プロキシに関する疑問を完全に解決できます。

  4. 上記のコードと結果からわかるように、invoke() メソッドを明示的に呼び出していませんが、このメソッドは実際に実行されました。プロセス全体を分析してみましょう:
  5. クライアントのコードから、突破口として newProxyInstance メソッドを使用できます。まず、Proxy クラスの newProxyInstance メソッドのソース コードを見てみましょう:
  6. Javaコード

  1. public static Object newProxyInstance(ClassLoader loader,

  2. Class>[] interfaces,

  3. InvocationHandler h )

  4. スロー IllegalArgumentException

  5. {

  6. if (h == null) {

  7. throw new NullPointerException();  

  8. }

  9. /*

  10. * 指定されたプロキシを検索または生成しますクラス。 

  11. */

  12. クラス cl = getProxyClass(loader, interfaces);  

  13. /*

  14. * 指定された 呼び出しハンドラーを使用して その コンストラクター を呼び出します。 

  15. */

  16. お試しください {

  17. /*

  18. * プロキシソースコード始まりにはこの定義があります:

  19. * private final static Class [] constructorParams = { InvocationHandler.class }; 

  20. * 短所は、InvocationHandler 型に参加する構築メソッド

  21. */

  22. コンストラクター cons = cl.getConstructor(constructorParams);  

  23. return (Object) cons.newInstance(new Object[] { h });  

  24. }

    catch (NoSuchMethodException e) {

  25. throw new InternalError(e.toString());  

  26. }

    catch (IllegalAccessException e) {

  27. throw new InternalError(e.toString());  

  28. }

    catch (InstantiationException e) {

  29. throw new InternalError(e.toString());  

  30. }

    catch (InvocationTargetException e) {

  31. throw new InternalError(e.toString());  

  32. }

  33. }



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) {

Java での動的プロキシの実装に関するチュートリアル }
    ...
  1. }

  2. Proxy を継承する $Proxy0 のソース コードを見てみましょう。
  3. Javaコード

    1. public final class $Proxy0 extends Proxy implements Subject {

    2. private static Method m1;  

    3. private static メソッド m0;  

    4. private static メソッド m3;  

    5. private static メソッド m2;  

    6. 静的 {

    7. 試してみる {

    8. m1 = Class.forName("java.lang.Object").getMethod("equals",

    9. new Class[] { Class.forName("java.lang.Object") });  

    10. m0 = Class.forName("java.lang.Object").getMethod("hashCode",

    11. 新しい クラス[0]);  

    12. m3 = Class.forName("***.RealSubject").getMethod("request",

    13. 新しい クラス[0]);  

    14. m2 = Class.forName("java.lang.Object").getMethod("toString",

    15. 新しい クラス[0]);  

    16. } catch (NoSuchMethodException no suchmethodException) {

    17. throw new NoSuchMethodError(no suchmethodException.getMessage());  

    18. } catch (ClassNotFoundException classnotfoundException) {

    19. throw new NoClassDefFoundError(classnotfoundException.getMessage() );  

    20. }

    21. } //static

    22. public $Proxy0(InvocationHand) ler invocationhandler) {

    23. super(invocationhandler);  

    24. }

    25. @Override

    26. public final boolean equals(Object obj) {

    27. 試してください {

    28. return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  

    29. } catch (Throwable スロー可能) {

    30. throw new UndeclaredThrowableException(throwable);  

    31. }

    32. }

    33. @オーバーライド

    34. public final int hashCode() {

    35. try {

    36. return ((Integer) super.h.invoke(this, m0, null)).intValue();  

    37. } catch (Throwable スロー可能) {

    38. throw new UndeclaredThrowableException(throwable);  

    39. }

    40. }

    41. public final void request() {

    42. 試してください {

    43. super.h。 invoke(this, m3, null);  

    44. 戻る;  

    45. } catch (エラーe) {

    46. } catch (Throwable throwable) {

    47. throw new UndeclaredThrowableException(throwable);  

    48. }

    49. }

    50. @オーバーライド

    51. public final String toString() {

    52. try {

    53. return (String) super.h.invoke(this, m2, null);  

    54. } catch (Throwable スロー可能) {

    55. throw new UndeclaredThrowableException(throwable);  

    56. }

    57. }

    58. }



次に、取得した $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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。