Dynamischer JAVA-Proxy
Proxy-Modus
Das Agentenmuster ist ein häufig verwendetes Java-Entwurfsmuster. Sein Merkmal besteht darin, dass die Agentenklasse und die Delegate-Klasse dieselbe Schnittstelle haben. Die Agentenklasse ist hauptsächlich für die Vorverarbeitung von Nachrichten für die Delegate-Klasse, das Filtern von Nachrichten und die Weiterleitung von Nachrichten an die Delegate-Klasse verantwortlich und die anschließende Verarbeitung von Nachrichten. Normalerweise besteht eine Assoziation zwischen einer Proxy-Klasse und einer Delegate-Klasse. Das Objekt der Proxy-Klasse selbst implementiert den Dienst nicht, sondern durch den Aufruf der entsprechenden Methoden des Objekts der Delegate-Klasse bestimmte Dienste bereitstellen.
Je nach Erstellungszeitraum des Agenten kann die Agentenklasse in zwei Typen unterteilt werden.
Statischer Proxy: Von Programmierern erstellt oder automatisch von einem bestimmten Tool generiert und dann kompiliert. Bevor das Programm ausgeführt wird, ist die .class-Datei der Proxy-Klasse bereits vorhanden.
Dynamischer Proxy: Wird mithilfe des Reflexionsmechanismus dynamisch erstellt, wenn das Programm ausgeführt wird.
Schauen Sie sich zunächst den statischen Proxy an:
1.Count.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao;
/**
* Definieren Sie eine Kontoschnittstelle
*
* @author-Administrator
*
*/
öffentliche Schnittstelle Anzahl {
// Kontomethode anzeigen
public void queryCount();
//Kontomethode ändern
public void updateCount();
}
2. CountImpl.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao.impl;
import net.battier.dao.Count;
/**
* Delegate-Klasse (einschließlich Geschäftslogik)
*
* @author-Administrator
*
*/
Die öffentliche Klasse CountImpl implementiert Count {
@Override
public void queryCount() {
System.out.println("Kontomethode anzeigen...");
}
@Override
public void updateCount() {
System.out.println("Kontomethode ändern...");
}
}
CountProxy.java
Paket net.battier.dao.impl;
import net.battier.dao.Count;
/**
* Dies ist eine Proxy-Klasse (erweiterte CountImpl-Implementierungsklasse)
*
* @author-Administrator
*
*/
Die öffentliche Klasse CountProxy implementiert Count {
private CountImpl countImpl;
/**
* Überschreiben Sie den Standardkonstruktor
*
* @param countImpl
*/
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
public void queryCount() {
System.out.println("Vor der Transaktionsverarbeitung");
// Rufen Sie die Methode der Delegate-Klasse auf;
countImpl.queryCount();
System.out.println("Nach der Transaktionsverarbeitung");
}
@Override
public void updateCount() {
System.out.println("Vor der Transaktionsverarbeitung");
// Rufen Sie die Methode der Delegate-Klasse auf;
countImpl.updateCount();
System.out.println("Nach der Transaktionsverarbeitung");
}
}
3. TestCount.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.test;
import net.battier.dao.impl.CountImpl;
import net.battier.dao.impl.CountProxy;
/**
*Test Count-Klasse
*
* @author-Administrator
*
*/
öffentliche Klasse TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
Wenn Sie den Code beobachten, können Sie feststellen, dass jede Proxy-Klasse nur eine Schnittstelle bedienen kann. Auf diese Weise werden während der Programmentwicklung zwangsläufig zu viele Proxy-Operationen generiert, mit Ausnahme der Methode, die sie aufrufen muss zu diesem Zeitpunkt wiederholt werden. Der beste Weg, dieses Problem zu lösen, besteht darin, eine Proxy-Klasse zu verwenden, um alle Proxy-Funktionen auszuführen. In diesem Fall muss ein dynamischer Proxy verwendet werden, um es abzuschließen.
Werfen wir einen Blick auf den dynamischen Proxy:
Der dynamische JDK-Proxy enthält eine Klasse und eine Schnittstelle:
InvocationHandler-Schnittstelle:
öffentliche Schnittstelle InvocationHandler {
public Object invoke(Object Proxy,Method method,Object[] args) throws Throwable;
}
Parameterbeschreibung:
Objekt-Proxy: Bezieht sich auf das Objekt, das als Proxy fungiert.
Methodenmethode: Die aufzurufende Methode
Object[] args: Parameter, die beim Aufruf der Methode erforderlich sind
Sie können sich eine Unterklasse der InvocationHandler-Schnittstelle als letzte Operationsklasse eines Proxys vorstellen, die ProxySubject ersetzt.
Proxy-Klasse:
Die Proxy-Klasse ist eine auf Proxy-Operationen spezialisierte Klasse. Diese Klasse kann zur dynamischen Generierung von Implementierungsklassen für eine oder mehrere Schnittstellen verwendet werden.
öffentliches statisches Objekt newProxyInstance(ClassLoader-Loader, Class<?>[]-Schnittstellen,
InvocationHandler h)
löst eine IllegalArgumentException aus
Parameterbeschreibung:
ClassLoader-Loader: Klassenlader
Class<?>[]-Schnittstellen: Alle Schnittstellen abrufen
InvocationHandler h: Rufen Sie die Unterklasseninstanz der InvocationHandler-Schnittstelle ab
Ps: Klassenlader
In der Methode newProxyInstance() ist eine Instanz der ClassLoader-Klasse erforderlich. In der Proxy-Klasse gibt es tatsächlich drei Hauptklassenlader.
Booststrap ClassLoader: Dieser Loader ist in C++ geschrieben und kann in der allgemeinen Entwicklung nicht gesehen werden;
Extension ClassLoader: Wird zum Laden von Erweiterungsklassen verwendet, die im Allgemeinen den Klassen im Verzeichnis jre/lib/ext entsprechen.
AppClassLoader: (Standard) lädt die durch classpath angegebene Klasse, den am häufigsten verwendeten Loader.
dynamischer Proxy
Im Gegensatz zur statischen Proxy-Klasse gibt es die dynamische Proxy-Klasse. Der Bytecode der dynamischen Proxy-Klasse wird beim Ausführen des Programms dynamisch durch den Java-Reflexionsmechanismus generiert, ohne dass Programmierer den Quellcode manuell schreiben müssen. Dynamische Proxy-Klassen vereinfachen nicht nur die Programmierarbeit, sondern verbessern auch die Skalierbarkeit von Softwaresystemen, da der Java-Reflexionsmechanismus jede Art von dynamischen Proxy-Klassen generieren kann. Die Proxy-Klasse und die InvocationHandler-Schnittstelle im Paket java.lang.reflect bieten die Möglichkeit, dynamische Proxy-Klassen zu generieren.
Beispiel für einen dynamischen Proxy:
1.BookFacade.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao;
öffentliche Schnittstelle BookFacade {
public void addBook();
}
2.BookFacadeImpl.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao.impl;
import net.battier.dao.BookFacade;
Die öffentliche Klasse BookFacadeImpl implementiert BookFacade {
@Override
public void addBook() {
System.out.println("Buchmethode hinzufügen...");
}
}
BookFacadeProxy.java
Paket net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Dynamische JDK-Proxy-Proxy-Klasse
*
* @author Student
*
*/
Die öffentliche Klasse BookFacadeProxy implementiert InvocationHandler {
privates Objektziel;
/**
* Binden Sie das Delegate-Objekt und geben Sie eine Proxy-Klasse zurück
* @param Ziel
* @zurückkehren
*/
öffentliches Objekt bind(Objektziel) {
this.target = Ziel;
//Proxy-Objekt abrufen
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //Um die Schnittstelle zu binden (dies ist ein Fehler, cglib gleicht diesen Fehler aus)
}
@Override
/**
* Aufrufmethode
*/
öffentlicher Objektaufruf (Objekt-Proxy, Methodenmethode, Objekt[]-Argumente)
wirft Throwable {
Objektergebnis=null;
System.out.println("Die Sache beginnt");
//Ausführungsmethode
result=method.invoke(target, args);
System.out.println("Ende der Dinge");
Ergebnis zurückgeben;
}
}
3. TestProxy.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.test;
import net.battier.dao.BookFacade;
import net.battier.dao.impl.BookFacadeImpl;
import net.battier.proxy.BookFacadeProxy;
öffentliche Klasse TestProxy {
public static void main(String[] args) {
BookFacadeProxy-Proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) Proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}
}
Der dynamische Proxy von JDK ist jedoch auf die Schnittstellenimplementierung angewiesen. Wenn einige Klassen die Schnittstelle nicht implementieren, kann der JDK-Proxy nicht verwendet werden, sodass der dynamische Proxy von cglib verwendet werden muss.
Dynamischer Cglib-Proxy
Der dynamische Proxy-Mechanismus des JDK kann nur Proxy-Klassen implementieren, die keine Schnittstellen implementieren können. Sein Prinzip besteht darin, eine Unterklasse für die angegebene Zielklasse zu generieren , aber da Vererbung verwendet wird, kann die endgültig geänderte Klasse nicht als Proxy verwendet werden.
Beispiel
1.BookFacadeCglib.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao;
öffentliche Schnittstelle BookFacade {
public void addBook();
}
2.BookCadeImpl1.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.dao.impl;
/**
* Dies ist eine Implementierungsklasse, die die Schnittstelle nicht implementiert
*
* @author Student
*
*/
öffentliche Klasse BookFacadeImpl1 {
public void addBook() {
System.out.println("Allgemeine Methode zum Hinzufügen von Büchern...");
}
}
3.BookFacadeProxy.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* Verwenden Sie den dynamischen cglib-Proxy
*
* @author Student
*
*/
Die öffentliche Klasse BookFacadeCglib implementiert MethodInterceptor {
privates Objektziel;
/**
* Proxy-Objekt erstellen
*
* @param Ziel
* @zurückkehren
*/
öffentliches Objekt getInstance(Objektziel) {
this.target = Ziel;
Enhancer Enhancer = new Enhancer();
Enhancer.setSuperclass(this.target.getClass());
// Callback-Methode
Enhancer.setCallback(this);
//Proxy-Objekt erstellen
return Enhancer.create();
}
@Override
// Callback-Methode
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy-Proxy) wirft Throwable {
System.out.println("Die Sache beginnt");
Proxy.invokeSuper(obj, args);
System.out.println("Ende der Dinge");
null zurückgeben;
}
}
4. TestCglib.java
Kopieren Sie den Codecode wie folgt:
Paket net.battier.test;
import net.battier.dao.impl.BookFacadeImpl1;
import net.battier.proxy.BookFacadeCglib;
öffentliche Klasse TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}