Der Schlüssel zur Implementierung dynamischer Proxy in Java sind diese beiden Dinge: Proxy und InvocationHandler. Beginnen wir mit der Invoke -Methode in der InvocationHandler -Schnittstelle und erklären Sie kurz, wie Java dynamischen Proxy implementiert.
Erstens lautet die vollständige Form der Invoke -Methode wie folgt:
öffentliches Objekt invoke (Object Proxy, Methode Methode, Object [] args) wirft Throwable {method.invoke (obj, args); return null;} ausNehmen wir zunächst an, dass die Methode die genannte Methode ist, dh die Methode, die ausgeführt werden muss. Args ist der Parameter der Methode; Proxy, was ist dieser Parameter? Die obige Implementierung der Invoke () -Methode ist eine relativ Standardform. Wir sehen, dass hier keine Proxyparameter verwendet werden. Schauen Sie sich die Beschreibung des Proxy in der JDK -Dokumentation wie folgt an:
Ein Methodenaufruf auf einer Proxy -Instanz über eine seiner Proxy -Schnittstellen wird an die Invoke -Methode des Aufrufhandlers der Instanz geschickt, wobei die Proxy -Instanz, ein Java.lang.reflect.Method -Objekt über die Identifizierung der aufgerufenen Methode und ein Array des Typs, das die Argumente enthält, übergeben wird.
Daraus können wir wissen, dass die obige Vermutung korrekt ist, und wir wissen auch, dass der Proxy -Parameter eine Instanz der Proxy -Klasse ist.
Zur Bequemlichkeit der Erklärung finden Sie hier ein einfaches Beispiel, um dynamischen Proxy zu implementieren.
// abstrakte Rolle (Dynamic Proxy Can nur Proxy Interface) öffentliche Schnittstelle Subjekt {public void request (); } // Reale Rolle: Implementierte die Request () -Methode der Subjektpublikumklasse RealSubject implementiert das Thema {public void request () {System.out.println ("From Real Subjekt"); }} // InvocationHandler Public Class DynamicicsUbject implementiert InvocationHandler {private Objekt obj; // Dies ist der Vorteil des dynamischen Proxy. Das eingekapselte Objekt ist vom Objekttyp und akzeptiert Objekte eines beliebigen Typs public dynamicsUbject () {} public dynamicsubject (Object obj) {this.obj = obj; } // Diese Methode ist nicht das, was wir zeigen, um das öffentliche Objekt aufzurufen (Object Proxy, Methode Methode, Object [] Args), löscht Throwable {System.out.println ("Bevor" + Methode) aus. method.invoke (obj, args); System.out.println ("nach dem Aufrufen" + Methode); null zurückkehren; }} // Client: Generieren Sie eine Proxyinstanz und rufen Sie die Request () -Methode-Klassen Client {public static void main (string [] args) aus, die throwable {// Todo automatisch generierte Methode Stub-Subjekt RS = New RealSubject (); // Geben Sie die Proxy-Klassen-InvocationHandler DS = New Dynamicsubject (RS) an; Klasse <?> Cls = rs.getClass (); // Folgendes ist eine einmalige Generation von Proxy-Subjekt = (Subjekt) proxy.newproxyinstance (cls.getClassloader (), cls.getInterfaces (), DS); // Hier können Sie beweisen, dass das Thema eine Instanz von Proxy ist, indem Sie die Ergebnisse ausführen. Diese Instanz implementiert das Subjekt -Schnittstellensystem. // Hier sehen Sie, dass die Klasse des Subjekts $ proxy0 ist. Diese $ proxy0 -Klasse erbt Proxy und implementiert das Subjekt -Schnittstellensystem. System.out.print ("Die Eigenschaften im Subjekt sind:"); Field [] field = Subjekt.getClass (). GetDeclaredfields (); für (Feld f: field) {System.out.print (f.getName ()+","); } Die Methoden in System.out.print ("/n"+"Subjekt sind:"); Method [] method = subjekt.getClass (). GetDeclaredMethods (); für (Methode M: Methode) {System.out.print (M.GetName ()+","); } Die übergeordnete Klasse von System.out.println ("/n"+"Betreff ist:"+subjekt.getClass (). GetuperClass ()); System.out.print ("/n"+"Subjekt implementiert die Schnittstelle:"); Klasse <?> [] Interfaces = subjekt.getClass (). GetInterfaces (); für (Klasse <?> I: Schnittstellen) {System.out.print (i.getName ()+","); } System.out.println ("/n/n"+"Run -Ergebnis ist:"); Betreff.Request (); }} Das Betriebsergebnis ist wie folgt: Der Paketname wird hier weggelassen, *** stattdessen
WAHR
Die Klasse der Subjekte lautet: Klasse $ proxy0
Die Eigenschaften des Subjekts sind: M1, M3, M0, M2,
Die Methoden in Subjekt sind: Anfrage, Hashcode, gleich
Die übergeordnete Klasse des Themas lautet: Klasse java.lang.reflect.proxy
Die von Subjekt implementierte Schnittstelle lautet: cn.edu.ustc.dynamicproxy.subject,
Das Betriebsergebnis ist:
Bevor Sie öffentliche abstrakte void ***. Subjekt.Request () anrufen
Aus echtem Thema.
Nachdem er öffentliche abstrakte void ***. Subjekt.Request () bezeichnet hat ()
PS: Die Informationen zu diesem Ergebnis sind zumindest für mich sehr wichtig. Da die Grundursache für meinen Schwindel im dynamischen Proxy darin besteht, dass ich das obige Subjekt missverstanden habe. Request (), zumindest war ich von der Oberfläche verwirrt und fand die Verbindung zwischen Subjekt und Proxy nicht. Ich war einmal verwirrt darüber, wie die letzte Anrufanfrage () mit Invoke () verbunden war und wie Invoke wusste, dass die Anfrage existiert. Tatsächlich können True und Class $ $ proxy0 oben viele Fragen lösen und mit dem Quellcode von $ proxy0 gekoppelt werden, der unten erwähnt wird. Er kann die Zweifel an dynamischem Proxy vollständig lösen.
Aus dem obigen Code und den obigen Ergebnissen können wir sehen, dass wir die IVOKE () -Methode nicht wie gezeigt aufgerufen haben, aber diese Methode wurde ausgeführt. Analysieren wir den gesamten folgenden Prozess:
Nach dem Code im Kunden zu urteilen, können Sie die NewProxyInstance -Methode als Durchbruch verwenden. Schauen wir uns zunächst den Quellcode der NewProxyInstance -Methode in der Proxy -Klasse an:
public statisches Objekt NewProxyInstance (Classloader Loader, Class <?> [] Schnittstellen, InvocationHandler H) löst IllegalArgumentException aus {if (h == null) {werfen neue nullpointerexception (); } / * * Schauen oder generieren Sie die entworfene Proxy -Klasse. */ Class cl = getProxyClass (Loader, Schnittstellen); / * * Rufen Sie seinen Konstruktor mit dem entworfenen Anrufer auf. * / try { / * * Der Proxy -Quellcode hat die folgende Definition: * private endgültige statische Klasse [] constructorParams = {invocationHandler.class}; * CONS ist die Konstruktormethode mit den formalen Parametern des InvocationHandler -Typs*/ Constructor Cons = Cl.GetConstructor (ConstructorParams); return (Object) con.Newinstance (neues Objekt [] {H}); } catch (NoSuchMethodException e) {neue InternalError werfen (e.toString ()); } catch (illegalAccessException e) {neue InternalError werfen (e.ToString ()); } catch (InstantiationException e) {neue InternalError werfen (e.ToString ()); } catch (invocationTargetException e) {neue InternalError werfen (e.toString ()); }} Proxy.NewProxyInstance (Classloader Loader, Class <?> [] Schnittstellen, InvocationHandler H) macht die folgenden Dinge.
(1) Rufen Sie die Methode GetProxyClass (Loader, Schnittstellen) basierend auf dem Parameter Loader und Schnittstellen auf, erstellen Sie die Proxy -Klasse $ proxy0.
(2) $ proxy0 instanziieren und dynamicsubject im Konstruktor übergeben, $ proxy0 ruft den Konstruktor des übergeordneten Klasse -Proxy auf und weist H wie folgt einen Wert zu::
Klasse Proxy {invocationHandler H = null; geschützter Proxy (invocationHandler h) {this.h = h; } ...}Schauen wir uns den Quellcode an, der den $ proxy0 von Proxy erbt:
öffentliche endgültige Klasse $ proxy0 erweitert Proxy implementiert Fach {private statische Methode M1; private statische Methode M0; private statische Methode M3; private statische Methode M2; static {try {m1 = class.forname ("java.lang.Object"). M0 = class.Forname ("java.lang.object"). getMethod ("HashCode", neue Klasse [0]); M3 = class.Forname ("***. RealSubject"). getMethod ("Anfrage", neue Klasse [0]); m2 = class.Forname ("java.lang.object"). getMethod ("tostring", neue Klasse [0]); } catch (NoSuchMethodException NoSuchMethodException) {neue NoSuchMethoDoderror werfen (NoSuchMethodException.getMessage ()); } catch (classNotFoundException classNotFoundException) {neue noclassDeffoundError werfen (classNotFoundException.getMessage ()); }} // static public $ proxy0 (invocationHandler invocationHandler) {Super (invocationHandler); } @Override public Final Boolean Equals (Objekt obj) {try {return ((boolean) super.h.invoke (this, m1, neues Objekt [] {obj}) .booleanValue (); } catch (Throwable Throwable) {werfen Sie neue nicht deklarierte Drüsenverfasstheit (Throwable); }} @Override public Final int hashCode () {try {return ((Integer) Super.H.Invoke (this, M0, null)). IntValue (); } catch (Throwable Throwable) {werfen Sie neue nicht deklarierte Drüsenverfasstheit (Throwable); }} public Final void request () {try {Super.h.invoke (this, M3, null); zurückkehren; } catch (error e) {} catch (throwable throwable) {werfen neu nicht deklarierte Drüsenabpfe (Throwable); }} @Override public Final String toString () {try {return (string) super.h.invoke (this, m2, null); } catch (Throwable Throwable) {werfen Sie neue nicht deklarierte Drüsenverfasstheit (Throwable); }}}Geben Sie dann die resultierende $ proxy0 -Instanz in ein Thema und weisen Sie den Verweis auf das Thema zu. Wenn die Methode des Subjekts.Request () ausgeführt wird, wird die Request () -Methode in der $ proxy0 -Klasse aufgerufen, und die Invoke () -Methode H in der übergeordneten Klasse Proxy wird aufgerufen. Das heißt, incallocationHandler.invoke ().
PS: 1. Eine Sache zu beachten ist, dass die GetProxyClass -Methode in der Proxy -Klasse die Klasse der Proxy zurückgibt. Der Grund dafür ist, dass ich zu Beginn einen Fehler auf niedriger Ebene gemacht habe und dachte, dass die Rückkehr "Klassenklasse der Proxy-Klasse" ist! Es wird empfohlen, sich den Quellcode von GetProxyClass anzusehen, was sehr lang ist. =
2. Aus dem Quellcode von $ proxy0 ist ersichtlich, dass die dynamische Proxy -Klasse nicht nur die Methoden in der Anzeige definierte Schnittstelle, sondern auch die ererbten drei Methoden von Equals (), HashCode () und ToString () im Root -Class -Objekt von Java und nur diesen drei Methoden profitiert.
F: Bisher gibt es noch eine Frage. Der erste Parameter in der Invoke -Methode ist eine Instanz von Proxy (um genau zu sein, wird die Instanz von $ proxy0 endgültig verwendet), aber wie verwendet es? Oder wie erscheint die Funktion im Programm?
A: Aus meiner aktuellen Ebene hat dieser Proxy -Parameter keinen Einfluss. Im gesamten dynamischen Proxy -Mechanismus wird der Proxy -Parameter der Invoke -Methode in InvocationHandler nicht verwendet. Der in übergebene Parameter ist tatsächlich eine Instanz der Proxy -Klasse. Ich denke, es könnte sein, dass Programmierer Reflexion in der Invoke -Methode verwenden, um Informationen über die Proxy -Klasse zu erhalten.
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels über die Invoke () -Methode in InvocationHandler. Ich hoffe, es wird für alle hilfreich sein. Interessierte Freunde können weiterhin auf diese Seite verweisen:
Detaillierte Erläuterung des statischen Federproxy und des dynamischen Proxycode
Beispiel für Spring -Framework -Abhängigkeitsmethode
Java -Programmierungsimplementierung von SpringMVC Simple Login Beispiel
Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen.