Das Aufkommen des dynamischen Java-Proxy-Mechanismus ermöglicht es Java-Entwicklern, Proxy-Klassen dynamisch zu erhalten, ohne Proxy-Klassen manuell schreiben zu müssen. Sie können einfach eine Reihe von Schnittstellen angeben und Klassenobjekte delegieren. (Empfohlen: Java-Video-Tutorial)
Die Proxy-Klasse ist für die Weiterleitung aller Methodenaufrufe an das Delegate-Objekt zur Reflexionsausführung verantwortlich. Während des Versandausführungsprozesses können Entwickler bei Bedarf auch Anpassungen vornehmen Delegieren Sie Klassenobjekte und ihre Funktionen. Dies ist ein sehr flexibles und flexibles Proxy-Framework. Als nächstes lernen wir dynamische Agenten kennen.
Eine kurze Beschreibung des dynamischen Proxys
Im dynamischen Proxy-Mechanismus von Java gibt es zwei wichtige Klassen oder Schnittstellen, eine davon ist InvocationHandler( Schnittstelle), das andere ist Proxy (Klasse).
1. Beschreibung des InvocationHandler (Schnittstelle):
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.
Jede dynamische Proxy-Klasse muss die InvocationHandler-Schnittstelle implementieren, und jede Proxy-Klasseninstanz ist zugeordnet, wenn wir einen Handler erreichen Wenn wir eine Methode über das Proxy-Objekt aufrufen, wird der Aufruf dieser Methode weitergeleitet, um von der Aufrufmethode der InvocationHandler-Schnittstelle aufgerufen zu werden. Werfen wir einen Blick auf die einzige Methode der InvocationHandler-Schnittstelle, die Aufrufmethode:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Diese Methode empfängt drei Parameter und gibt einen Objekttyp zurück. Ihre jeweiligen Bedeutungen sind wie folgt:
proxy: bezieht sich auf das reale Objekt, das wir darstellen
Methode: bezieht sich auf das Methodenobjekt, das wir als Methode des realen Objekts aufrufen möchten
args: bezieht sich auf die Parameter, die beim Aufruf einer Methode des realen Objekts empfangen werden Objekt Das vom Parameter
zurückgegebene Objekt bezieht sich auf den Rückgabetyp der realen Objektmethode. Das Obige wird in den folgenden Beispielen ausführlicher verstanden.
the value to return from the method invocation on the proxy instance.
2. Beschreibung des Proxys (Klasse):
Proxy stellt statische Methoden zum Erstellen dynamischer Proxy-Klassen und -Instanzen bereit und ist auch die Oberklasse aller von diesen Methoden erstellten dynamischen Proxy-Klassen.
Die Funktion der Proxy-Klasse besteht darin, dynamisch ein Proxy-Objekt zu erstellen. Wir verwenden häufig die newProxyInstance-Methode:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Verständnis der Parameter:
// 一个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
Verständnis der Rückgabeergebnisse: Eine Instanz eines Proxy-Objekts
eine Proxy-Instanz mit dem angegebenen Aufrufhandler einer Proxy-Klasse, die durch den angegebenen Klassenlader definiert wird und die angegebenen Schnittstellen implementiert
Einfacher Java-Proxy
Wir erstellen ein Java-Projekt zum Testen und Verständnis des dynamischen Proxys. Die Projektstruktur ist wie folgt:
1. Definieren Sie zunächst eine Schnittstelle und fügen Sie zwei Methoden hinzu.
package com.huhx.proxy; public interface Interface { void getMyName(); String getNameById(String id); }
2. Definieren Sie eine echte Klasse, die die obige Schnittstelle implementiert, 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. Definieren Sie ein Proxy-Objekt, das auch ist implementiert Die oben genannte Interface-Schnittstelle:
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 testet die oben genannten Ergebnisse in der Main-Methode:
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. Das Ausführen Die Ergebnisse sind wie folgt:
my name is huhx argument id: 1 name: huhx ======================================================== proxy getmyname my name is huhx proxy getnamebyid argument id: 1 name: huhx
Dynamischer Java-Proxy
Nachdem wir den oben genannten einfachen Java-Proxy fertiggestellt haben, beginnen wir nun, Java zu lernen Dynamischer Proxy. Es geht einen Schritt weiter als die Idee von Proxys, da es Proxys dynamisch erstellen und Aufrufe der Proxy-Methoden dynamisch verarbeiten kann. Alle über den dynamischen Proxy getätigten Anrufe werden an einen einzelnen Anrufabwickler umgeleitet, dessen Aufgabe es ist, die Art des Anrufs offenzulegen und die geeignete Gegenmaßnahme zu ermitteln. Im Folgenden verwenden wir Fälle, um unser Verständnis der dynamischen Java-Proxys zu vertiefen:
1. Erstellen Sie einen Prozessor, der InvocationHandler erbt: 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. Wir schreiben A test Main-Methode, 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. Die laufenden Ergebnisse sind wie folgt:
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
Aus den obigen Ausgabeergebnissen können wir die folgenden Schlussfolgerungen ziehen :
Der mit dem Proxy-Objekt verknüpfte InvocationHandler führt seine Aufrufmethode nur aus, wenn das Proxy-Objekt eine Methode aufruft
Verständnis der drei Parameter von invoke: Objekt-Proxy ist das Objekt des Proxys, Die Methodenmethode ist die Methodenklasse, die die Methode im realen Objekt aufruft. Object[] args sind die Parameter, die die Methode im realen Objekt aufrufen
Das Prinzip des dynamischen Java-Proxys
1. Der Schlüsselcode des dynamischen Proxys ist Proxy.newProxyInstance(classLoader, interfaces, handler) und werfen wir einen Blick darauf:
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. Werfen wir einen Blick auf den Quellcode der newInstance-Methode:
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. Wenn wir eine Methode über das Proxy-Objekt aufrufen, erfolgt der Aufruf dieser Methode an die invoke-Methode des InvocationHandler-Schnittstellenaufrufs weitergeleitet.
Ich konnte den Code, der diesen Satz verkörpert, im Quellcode nicht finden, daher habe ich den folgenden Code zur Hauptmethode der Testklasse hinzugefügt:
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基础教程栏目。
Das obige ist der detaillierte Inhalt vonDas Prinzip des dynamischen Java-Proxys. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!