プロキシは何ですか
他のオブジェクトへのオブジェクトへのアクセスを制御するためのプロキシを提供します。いくつかのケースでは、オブジェクトは適切ではないか、直接、別のオブジェクトを参照しない、プロキシオブジェクトは、クライアントとターゲットオーディエンスの間の仲介の役割を果たすことができます。 - Baiduの百科事典から
もっと単純に、それは我々が調停に住んでいるということです
ダイナミックエージェントとは何ですか
ダイナミックエージェントが動的に作成するためにバイトコードの実行時に反射によって作動するバイトコードファイルを、ひいてはプロキシオブジェクトを作成します。
コードの最初の、言っても過言ではありません
- インターフェイスを作成します。
public interface OutInfo {
void printInfo();
}
- 実装クラスを作成します:
public class Person implements OutInfo {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public void printInfo() {
System.out.println(name + "..." + age);
}
}
- 動的プロキシデモを書きます
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
Person person = new Person("张三", 23);
OutInfo oi = (OutInfo) Proxy.newProxyInstance(
Person.class.getClassLoader(),
Person.class.getInterfaces(),
/*
* 此代码基于JDK8编写,所以用到了Lambda表达式
*/
(proxy, method, arg) -> {
System.out.println("方法前处理");
/*
* 注意:invoke()的第一个参数只能写被代理对象的实例
* 不能写参数proxy,否则会栈溢出,原因后面讲解
*/
Object ret = method.invoke(person, arg);
System.out.println("方法后处理");
return ret;
}
);
oi.printInfo();
}
}
結果を見てください:
操作の結果を見ると、薬の結果は問題ありません。だから、のようなエージェント・プロセスは何ですか?
演技のプロセス分析
ダイナミックプロキシは、バイトコードを操作することにより、動的プロキシオブジェクトを作成することである前に、どのようないくつかの内部のバイトコードファイルを生成し、その後、我々はそれを見て、言いました:
ああ、バイトコードファイルに次のコードを介して使用できるが、動的プロキシを生成しますが、別のJREができるが必要です!推奨されるJDK8!!!
public void saveProxyClassFile(){
// 参数:(生成的字节吗对象的名字,被代理对象实现的接口数组)
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{OutInfo.class});
try(
FileOutputStream fos =new FileOutputStream(new File("$Proxy.class"))
){
fos.write(bytes);
fos.flush();
}catch (Exception e) {
e.printStackTrace();
}
}
これは、考え方によって翻訳されたデコンパイラのコンテンツを付属しています。
public final class $Proxy extends Proxy implements OutInfo {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void printInfo() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("ann.study.OutInfo").getMethod("printInfo");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
変換されたコードを読み取ることによって、私たちは、保存された変数立方メートルを知ることができる方法のオブジェクト・インタフェース、および生成されたプロキシ方式であるprintInfo()
コードのように行に:
super.h.invoke(this, m3, (Object[])null);
ここで、hは我々は匿名のオブジェクトに渡されたラムダ式を使用して、このメソッドの役割は、オーバーライドされた私たちを呼び出すためにあるものであるinvoke()
方法。
実際には、この方法は、このようなものです:
public Object invoke(Object proxy, Method method, Object[] args)
パラメータ対応の後、我々は、プロキシパラメータの役割を知っているだろう、との動的プロキシデモmethod.invoke(person, arg)
書かれたプロキシが理由のスタックオーバーフローを引き起こす可能性があります:
> 递归调用引起了死循环,程序无法结束循环,所以会报栈溢出异常
このメカニズムを通じて、JDKの動的プロキシが完了します
要約します
- 動的プロキシは、バイトコードファイルを操作することにより、プロキシオブジェクトを生成するために使用され、これは、プロキシクラスを生成するために、静的なエージェントを解決するだろう多くの困難とメンテナンスの問題です
- 例えば、いくつかのピットの動的プロキシ、:
- JDKは、プロキシオブジェクトが実装クラスのインターフェイスに返された動的プロキシプロキシクラスがインタフェースを実装しなければならない必要とされ、インターフェースが実装したくない場合は、CGLIBを使用することができます
- 実装のInvocationHandlerインタフェースの書き換えに
incvoke()
時間法、に注意を払うmethod.invoke()
プロキシオブジェクトに渡される最初の引数、書き換え渡すことはできませんinvoke()
最初の引数を、引数があるため、プロキシオブジェクトということです。
これは間違った場所にブログの記事やコンテンツを書くブロガーはまた、私はコメントを修正してください、私はあなたが私と一緒にクマを願って初めてです。最後に、私のブログの記事を読んでいただきありがとうございます。