ホームページ  >  記事  >  Java  >  Java の Proxy メカニズムの詳細な分析

Java の Proxy メカニズムの詳細な分析

黄舟
黄舟オリジナル
2017-10-13 10:10:471456ブラウズ

この記事では主に Java プロキシ メカニズムの詳細な解釈を紹介します。必要な方はぜひ参考にしてください。

動的プロキシは実際には、指定したすべてのインターフェイスに基づいてクラス バイトを動的に生成する java.lang.reflect.Proxy クラスです。このクラスは Proxy クラスを継承し、指定したすべてのインターフェイス (パラメータ)配列); 次に、指定したクラスローダーを使用してクラスバイトをシステムにロードし、最後にそのようなクラスのオブジェクトを生成し、対応するメソッドメンバーである invocationHandler などのオブジェクトのいくつかの値を初期化します。すべてのインターフェースに。 初期化後、オブジェクトは呼び出し元のクライアントに返されます。このようにして、クライアントはすべてのインターフェイスを実装する Proxy オブジェクトを取得します。分析例を参照してください:

1. ビジネスインターフェースクラス


public interface BusinessProcessor {
 public void processBusiness();
}

2. ビジネス実装クラス


public class BusinessProcessorImpl implements BusinessProcessor {
 public void processBusiness() {
 System.out.println("processing business.....");
 }
}

3. ビジネスエージェントクラス


りー

4 人の顧客 アプリケーション クラスの終了


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BusinessProcessorHandler implements InvocationHandler {
 private Object target = null;
 BusinessProcessorHandler(Object target){
 this.target = target;
 }
 public Object invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
 System.out.println("You can do something here before process your business");
 Object result = method.invoke(target, args);
 System.out.println("You can do something here after process your business");
 return result;
 }
}

次に、印刷結果を見てみましょう:


import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
public class Test {
 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 }
}

結果を通して、プロキシの役割を簡単に確認できます。コア ビジネス メソッドの後に、ロギングやセキュリティ メカニズムなど、実行したい補助的な作業を追加します。

それでは、上記のクラスがどのように動作するかを分析してみましょう。

カテゴリー 1 と 2 については特に言うことはありません。まずはカテゴリー 3 を見てみましょう。 InvocationHandlerインターフェースのinvokeメソッドを実装します。実際、このクラスは、プロキシによって最終的に呼び出される固定インターフェイス メソッドです。プロキシは、クライアントのビジネス メソッドがどのように実装されているかは関係ありません。クライアントが Proxy を呼び出すときは、InvocationHandler の invoke インターフェイスのみを呼び出すため、実際に実装されたメソッドは invoke メソッドで呼び出す必要があります。関係は次のとおりです:


You can do something here before process your business
processing business.....
You can do something here after process your business

それでは、bp はどのようなオブジェクトですか? main メソッドを変更して見てみましょう:


 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();

出力結果:


 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 System.out.println(bp.getClass().getName());
 }

bp は $Proxy0 クラスのオブジェクトであることがわかります。それで、このクラスはどのようなものですか?わかりましたこのクラスを出力するメソッドをさらに 2 つ書いて、3 つの頭と 6 本の腕がどのようなものか見てみましょう。 main の下に次の 2 つの静的メソッドを記述します。


You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0

main メソッドを書き換えます


public static String getModifier(int modifier){
 String result = "";
 switch(modifier){
  case Modifier.PRIVATE:
  result = "private";
  case Modifier.PUBLIC:
  result = "public";
  case Modifier.PROTECTED:
  result = "protected";
  case Modifier.ABSTRACT :
  result = "abstract";
  case Modifier.FINAL :
  result = "final";
  case Modifier.NATIVE :
  result = "native";
  case Modifier.STATIC :
  result = "static";
  case Modifier.SYNCHRONIZED :
  result = "synchronized";
  case Modifier.STRICT :
  result = "strict";
  case Modifier.TRANSIENT :
  result = "transient";
  case Modifier.VOLATILE :
  result = "volatile";
  case Modifier.INTERFACE :
  result = "interface";
 }
 return result;
 }
 public static void printClassDefinition(Class clz){
 String clzModifier = getModifier(clz.getModifiers());
 if(clzModifier!=null && !clzModifier.equals("")){
  clzModifier = clzModifier + " ";
 }
 String superClz = clz.getSuperclass().getName();
 if(superClz!=null && !superClz.equals("")){
  superClz = "extends " + superClz;
 }
 Class[] interfaces = clz.getInterfaces();
 String inters = "";
 for(int i=0; i<interfaces.length; i++){
  if(i==0){
  inters += "implements ";
  }
  inters += interfaces[i].getName();
 }
 System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
 System.out.println("{");
 Field[] fields = clz.getDeclaredFields();
 for(int i=0; i<fields.length; i++){
  String modifier = getModifier(fields[i].getModifiers());
  if(modifier!=null && !modifier.equals("")){
  modifier = modifier + " ";
  }
  String fieldName = fields[i].getName();
  String fieldType = fields[i].getType().getName();
  System.out.println("  "+modifier + fieldType + " "+ fieldName + ";");
 }
 System.out.println();
 Method[] methods = clz.getDeclaredMethods();
 for(int i=0; i<methods.length; i++){
  Method method = methods[i];
  String modifier = getModifier(method.getModifiers());
  if(modifier!=null && !modifier.equals("")){
  modifier = modifier + " ";
  }
  String methodName = method.getName();
  Class returnClz = method.getReturnType();
  String retrunType = returnClz.getName();
  Class[] clzs = method.getParameterTypes();
  String paraList = "(";
  for(int j=0; j<clzs.length; j++){
  paraList += clzs[j].getName();
  if(j != clzs.length -1 ){
   paraList += ", ";
  }
  }
  paraList += ")";
  clzs = method.getExceptionTypes();
  String exceptions = "";
  for(int j=0; j<clzs.length; j++){
  if(j==0){
   exceptions += "throws ";
  }
  exceptions += clzs[j].getName();
  if(j != clzs.length -1 ){
   exceptions += ", ";
  }
  }
  exceptions += ";";
  String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
  System.out.println("  "+methodPrototype );
 }
 System.out.println("}");
 }

次に、出力を見てみましょう:


 public static void main(String[] args) {
 BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
 BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
 BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
 bp.processBusiness();
 System.out.println(bp.getClass().getName());
 Class clz = bp.getClass();
 printClassDefinition(clz);
 }

明らかに、Proxy.newProxyInstance メソッドは次のことを行います。

1.渡された 2 番目のパラメーター インターフェイスに基づいてクラスを動的に生成し、インターフェイスにインターフェイスを実装します。この例では、BusinessProcessor インターフェイスの processBusiness メソッドです。そしてProxyクラスを継承し、hashcode、toString、equalsの3つのメソッドを書き換えます。具体的な実装については、ProxyGenerator.generateProxyClass(...); を参照してください。 この例では、$Proxy0 クラス

2 が生成され、最初のパラメーターで渡されたクラスローダーを通じて新しく生成されたクラスが jvm にロードされます。 $Proxy0 クラス

3 をロードしようとしています。3 番目のパラメーターを使用して $Proxy0 の $Proxy0 (InvocationHandler) コンストラクターを呼び出して $Proxy0 のオブジェクトを作成し、interfaces パラメーターを使用してそのすべてのインターフェイスのメソッドを走査します。そしてメソッドオブジェクト初期化オブジェクトを生成します。いくつかのメソッドメンバー変数

4は$Proxy0のインスタンスをクライアントに返します。
もう大丈夫です。クライアントがそれをどのように調整するかを見てみましょう。そうすれば明らかになるでしょう。

1. クライアントが取得するのは$Proxy0のインスタンスオブジェクトです。$Proxy0はBusinessProcessorを継承しているため、BusinessProcessorに変換しても問題ありません。


You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0
$Proxy0 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
  java.lang.reflect.Method m4;
  java.lang.reflect.Method m2;
  java.lang.reflect.Method m0;
  java.lang.reflect.Method m3;
  java.lang.reflect.Method m1;
  void processBusiness();
  int hashCode();
  boolean equals(java.lang.Object);
  java.lang.String toString();
}

2, bp.processBusiness();


実際に $Proxy0.processBusiness() を呼び出すと、$Proxy0.processBusiness() の実装は InvocationHandler を通じてメソッドを呼び出します!

まとめ

以上がJava の Proxy メカニズムの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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