In diesem Artikel werden hauptsächlich relevante Informationen zu den detaillierten Beispielen des dynamischen Proxy-Mechanismus von Java vorgestellt. Ich hoffe, dass jeder, der den dynamischen Proxy-Mechanismus beherrscht, sich auf
beziehen kann Dynamischer Proxy-Mechanismus
Wenn wir Spring lernen, wissen wir, dass Spring hauptsächlich zwei Hauptideen hat, eine ist IoC und die andere ist AOP. Unnötig zu erwähnen, dass es sich um IoC, Abhängigkeitsinjektion und Springs Kern-AOP handelt Das heißt, wir müssen nicht nur wissen, wie wir unsere Funktionen durch AOP erfüllen, sondern auch das zugrunde liegende Prinzip lernen. Das Prinzip von AOP ist der dynamische Proxy-Mechanismus von Java, daher ist dieser Aufsatz eine Einführung in Java A Überprüfung dynamischer Mechanismen.
Im dynamischen Proxy-Mechanismus von Java gibt es zwei wichtige Klassen oder Schnittstellen, eine ist InvocationHandler (Schnittstelle) und die andere ist Proxy (Klasse). Diese Klasse und Schnittstelle implementieren unseren dynamischen Proxy gebraucht. Schauen wir uns zunächst an, wie das Java-API-Hilfedokument diese beiden Klassen beschreibt:
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.
Jede Klasse muss eine dynamische Proxy-Klasse sein Implementieren Sie die InvocationHandler-Schnittstelle, und jede Proxy-Klasseninstanz ist einem Handler zugeordnet. Wenn wir eine Methode über das Proxy-Objekt aufrufen, wird der Aufruf dieser Methode an die InvocationHandler-Schnittstelle weitergeleitet, um den Aufruf durchzuführen. Werfen wir einen Blick auf die Invoke-Methode, die einzige Methode der InvocationHandler-Schnittstelle:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Wir sehen, dass diese Methode insgesamt drei Parameter akzeptiert, also diese drei Parameter stellen Was dar?
Proxy: bezieht sich auf das reale Objekt, das wir als Proxy verwenden.
Methode: bezieht sich auf das Methodenobjekt, das wir als Methode des realen Objekts aufrufen möchten.
Argumente: bezieht sich auf die Methode zum Aufrufen des reales Objekt Wenn Sie die von einer bestimmten Methode akzeptierten Parameter
nicht verstehen, werde ich diese Parameter später anhand eines Beispiels ausführlich erläutern.
Als nächstes werfen wir einen Blick auf die Proxy-Klasse:
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
Die Funktion der Proxy-Klasse besteht darin, dynamisch ein Proxy-Objekt zu erstellen Es gibt viele Methoden, aber die, die wir am häufigsten verwenden, ist die newProxyInstance-Methode:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
Diese Methode Die Funktion besteht darin, Holen Sie sich ein dynamisches Proxy-Objekt, das drei Parameter empfängt. Schauen wir uns die Bedeutung dieser drei Parameter an:
loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载 interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
Okay, nach der Einführung dieser beiden Schnittstellen (Klassen). ), schauen wir uns ein Beispiel an, um zu sehen, wie unser dynamischer Proxy-Modus aussieht:
Zuerst definieren wir eine Schnittstelle vom Typ „Subject“ und deklarieren sie. Zwei Methoden:
public interface Subject { public void rent(); public void hello(String str); }
Dann wird eine Klasse definiert, um diese Schnittstelle zu implementieren. Diese Klasse ist unser eigentliches Objekt, die RealSubject-Klasse:
public class RealSubject implements Subject { @Override public void rent() { System.out.println("I want to rent my house"); } @Override public void hello(String str) { System.out.println("hello: " + str); } }
Der nächste Schritt ist Um eine dynamische Proxy-Klasse zu definieren, muss jede dynamische Proxy-Klasse die InvocationHandler-Schnittstelle implementieren, sodass unsere dynamische Proxy-Klasse dies nicht tut. Ausnahme:
public class DynamicProxy implements InvocationHandler { // 这个就是我们要代理的真实对象 private Object subject; // 构造方法,给我们要代理的真实对象赋初值 public DynamicProxy(Object subject) { this.subject = subject; } @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after rent house"); return null; } }
Schließlich: Werfen wir einen Blick auf unsere Client-Klasse:
public class Client { public static void main(String[] args) { // 我们要代理的真实对象 Subject realSubject = new RealSubject(); // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject .getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("world"); } }
Beginnen wir mit Werfen wir einen Blick auf die Konsolenausgabe:
$Proxy0 before rent house Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent() I want to rent my house after rent house before rent house Method:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String) hello: world after rent house
Schauen wir uns zunächst $Proxy0 an. Wir sehen, dass dieses Ding von System.out.println( subject.getClass().getName()) generiert wird. Warum ist das so? Klassenname des Proxy-Objekts, das wir so zurückgeben?
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject .getClass().getInterfaces(), handler);
Vielleicht dachte ich, dass das zurückgegebene Proxy-Objekt ein Objekt vom Typ „Subject“ oder ein InvocationHandler-Objekt sein würde, aber es stellte sich heraus, dass es nicht der Fall war. Lassen Sie uns erklären, warum wir hier sind. Kann es in ein Objekt vom Typ Subjekt konvertiert werden? Der Grund dafür ist, dass wir im zweiten Parameter der newProxyInstance-Methode eine Reihe von Schnittstellen für dieses Proxy-Objekt bereitstellen und mein Proxy-Objekt diese Schnittstellen dann natürlich implementiert. Zu diesem Zeitpunkt können wir natürlich die Typkonvertierung dieses Proxy-Objekts erzwingen . Es handelt sich um eine beliebige dieser Schnittstellen. Da die Schnittstelle hier vom Typ „Subjekt“ ist, kann sie in den Typ „Subjekt“ konvertiert werden.
Gleichzeitig müssen wir bedenken, dass das über Proxy.newProxyInstance erstellte Proxy-Objekt ein Objekt ist, das dynamisch generiert wird, wenn der JVM ausgeführt wird. Es ist weder unser InvocationHandler-Typ noch der Typ der Menge Schnittstellen, die wir definiert haben, aber ein Objekt, das zur Laufzeit dynamisch generiert wird, und die Benennungsmethode hat diese Form, beginnend mit $, Proxy befindet sich in der Mitte und die letzte Zahl stellt die Bezeichnung des Objekts dar.
Dann werfen wir einen Blick auf diese beiden Sätze
subject.rent(); subject.hello(“world”);
Hier sind Methoden in der Schnittstelle, die zu diesem Zeitpunkt durch Proxy-Objekte implementiert werden Springen Sie zur Ausführung zur Aufrufmethode im Handler, der diesem Proxy-Objekt zugeordnet ist, und unser Handlerobjekt akzeptiert einen Parameter vom Typ RealSubject. Dies bedeutet, dass ich dieses reale Objekt als Proxy verwenden möchte, also zu diesem Zeitpunkt Die Aufrufmethode im Handler wird zur Ausführung aufgerufen:
public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method:" + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("after rent house"); return null; }
我们看到,在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,同时我们看到我们的这个 method 对象是这样的:
public abstract void com.xiaoluo.dynamicproxy.Subject.rent() public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
正好就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。
这就是我们的java动态代理机制。
本篇随笔详细的讲解了java中的动态代理机制,这个知识点非常非常的重要,包括我们Spring的AOP其就是通过动态代理的机制实现的,所以我们必须要好好的理解动态代理的机制。
Das obige ist der detaillierte Inhalt vonDetaillierte Analyse des dynamischen Proxy-Mechanismus in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!