Java 動的プロキシ メカニズムの出現により、Java 開発者は、プロキシ クラスを手動で作成することなく、インターフェイスのセットとデリゲート クラス オブジェクトを指定するだけで、プロキシ クラスを動的に取得できるようになります。 (推奨: Java ビデオ チュートリアル )
プロキシ クラスは、リフレクション実行のためにすべてのメソッド呼び出しをデリゲート オブジェクトにディスパッチする責任を負います。ディスパッチ実行プロセス中に、開発者は必要に応じて調整することもできますデリゲート クラス オブジェクトとその関数。これは非常に柔軟で柔軟なプロキシ フレームワークです。次に、動的エージェントについて学び始めます。
動的プロキシの簡単な説明
Java の動的プロキシ メカニズムには、2 つの重要なクラスまたはインターフェイスがあります。1 つは InvocationHandler( Interface )、もう 1 つはプロキシ (クラス) です。
1. InvocationHandler (インターフェイス) の説明:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
すべての動的プロキシ クラスは InvocationHandler インターフェイスを実装する必要があり、各プロキシ クラスのインスタンスは、プロキシ オブジェクトを通じてメソッドを呼び出すと、このメソッドの呼び出しは、InvocationHandler インターフェイスの invoke メソッドによって呼び出されるように転送されます。 InvocationHandler インターフェイスの唯一のメソッドである invoke メソッドを見てみましょう:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
このメソッドは 3 つのパラメータを受け取り、オブジェクト タイプを返します。それぞれの意味は次のとおりです:
proxy:プロキシしている実際のオブジェクトを参照します。
method: 実際のオブジェクトのメソッドを呼び出したい Method オブジェクトを参照します。
args: のメソッドを呼び出すときに受け取られるパラメータを参照します。実際のオブジェクト パラメータ
によって返されるオブジェクトは、実際のオブジェクト メソッドの戻り値の型を参照します。上記については、次の例で詳しく理解します。
the value to return from the method invocation on the proxy instance.
2. プロキシ (クラス) の説明:
プロキシは、動的プロキシ クラスとインスタンスを作成するための静的メソッドを提供し、それらのメソッドによって作成されるすべての動的プロキシ クラスのスーパークラスでもあります。
Proxy クラスの機能は、プロキシ オブジェクトを動的に作成することです。よく newProxyInstance メソッドを使用します。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
パラメーターの理解:
// 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 loader - the class loader to define the proxy class // 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口 interfaces - the list of interfaces for the proxy class to implement // 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上 h - the invocation handler to dispatch method invocations to
戻り結果の理解: プロキシ オブジェクトのインスタンス
指定された呼び出しハンドラーを持つプロキシ インスタンス指定されたクラス ローダーによって定義され、指定されたインターフェイスを実装するプロキシ クラスの
単純な Java プロキシ
動的プロキシのテストと理解のために Java プロジェクトを作成します。プロジェクト構造は次のとおりです。
# 1. まずインターフェイス Interface を定義し、2 つのメソッドを追加します。
package com.huhx.proxy; public interface Interface { void getMyName(); String getNameById(String id); }
2. 上記のインターフェイス RealObject を実装する実際のクラスを定義します:
package com.huhx.proxy; public class RealObject implements Interface { @Override public void getMyName() { System.out.println("my name is huhx"); } @Override public String getNameById(String id) { System.out.println("argument id: " + id); return "huhx"; } }
3. プロキシ オブジェクトを定義します。実装された上記のインターフェイス インターフェイス:
package com.huhx.proxy; public class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied = proxied; } @Override public void getMyName() { System.out.println("proxy getmyname"); proxied.getMyName(); } @Override public String getNameById(String id) { System.out.println("proxy getnamebyid"); return proxied.getNameById(id); } }
4. SimpleMain Main メソッドで、上記の結果をテストします:
package com.huhx.proxy; public class SimpleMain { private static void consume(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) { consume(new RealObject()); System.out.println("========================================================"); consume(new SimpleProxy(new RealObject())); } }
5. 実行結果:
my name is huhx argument id: 1 name: huhx ======================================================== proxy getmyname my name is huhx proxy getnamebyid argument id: 1 name: huhx
Java の動的プロキシ
上記の単純な Java プロキシを完了したら、今度は Java の動的プロキシを学習し始めます。プロキシ。プロキシを動的に作成し、プロキシされたメソッドへの呼び出しを動的に処理できるため、プロキシの概念よりも一歩進んでいます。ダイナミック プロキシ上で行われたすべての呼び出しは、単一のコール ハンドラーにリダイレクトされます。その役割は、呼び出しのタイプを明らかにし、適切な対応策を決定することです。以下では、Java 動的プロキシの理解を深めるためにケースを使用します。
1. InvocationHandler を継承するプロセッサを作成します。 DynamicProxyHandler
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; public class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { System.out.println("dynamic proxy handler constuctor: " + proxied.getClass()); this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic proxy name: " + proxy.getClass()); System.out.println("method: " + method.getName()); System.out.println("args: " + Arrays.toString(args)); Object invokeObject = method.invoke(proxied, args); if (invokeObject != null) { System.out.println("invoke object: " + invokeObject.getClass()); } else { System.out.println("invoke object is null"); } return invokeObject; } }
2. A を書きます。 test Main メソッド、DynamicProxyMain:
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.huhx.proxy.Interface; import com.huhx.proxy.RealObject; public class DynamicProxyMain { public static void consumer(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) throws Exception, SecurityException, Throwable { RealObject realObject = new RealObject(); consumer(realObject); System.out.println("=============================="); // 动态代理 ClassLoader classLoader = Interface.class.getClassLoader(); Class<?>[] interfaces = new Class[] { Interface.class }; InvocationHandler handler = new DynamicProxyHandler(realObject); Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler); System.out.println("in dynamicproxyMain proxy: " + proxy.getClass()); consumer(proxy); } }
3. 実行結果は次のとおりです:
my name is huhx argument id: 1 name: huhx ============================== dynamic proxy handler constuctor: class com.huhx.proxy.RealObject in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0 dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null dynamic proxy name: class com.sun.proxy.$Proxy0 method: getNameById args: [1] argument id: 1 invoke object: class java.lang.String name: huhx
上記の出力結果から、次の結論を引き出すことができます。 :
プロキシ オブジェクトに関連付けられた InvocationHandler は、プロキシ オブジェクトがメソッドを呼び出した場合にのみ、その invoke メソッドを実行します。
invoke の 3 つのパラメータの理解: オブジェクト プロキシはプロキシのオブジェクトです, Method メソッドは実際のオブジェクトでメソッドを呼び出す Method クラス、Object[] args は実際のオブジェクトで呼び出されるメソッドのパラメータです
#Java 動的の原理proxy
1. 動的プロキシのキー コードは Proxy.newProxyInstance(classLoader, Interfaces, handler) です。ソース コードに従って見てみましょう:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // handler不能为空 if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ // 通过loader和接口,得到代理的Class对象 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { // 创建代理对象的实例 return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
2. newInstance メソッドのソース コードを見てみましょう:
private static Object newInstance(Constructor<?> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString()); } } }
3. プロキシ オブジェクトを通じてメソッドを呼び出すと、この呼び出しが行われます。メソッドは、InvocationHandler インターフェースの invoke メソッドに転送されます。
この文を反映したコードがソース コードに見つからなかったので、テスト クラスの main メソッドに次のコードを追加しました。if (proxy instanceof Proxy) { InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy); invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null); System.out.println("--------------------------------------"); }
这段代码的输出结果如下,与上述中调用代理对象中的getMyName方法输出是一样的,不知道Jvm底层是否是这样判断的:
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null --------------------------------------
更多java知识请关注java基础教程栏目。
以上がJava動的プロキシの原理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

SublimeText3 中国語版
中国語版、とても使いやすい

Dreamweaver Mac版
ビジュアル Web 開発ツール

SublimeText3 英語版
推奨: Win バージョン、コードプロンプトをサポート!
