Dynamischer Proxy von JAVA
Agent-Modus
Der Proxy-Modus ist ein häufig verwendetes Java-Entwurfsmuster. Sein Merkmal besteht darin, dass die Proxy-Klasse und die Delegate-Klasse dieselbe Schnittstelle haben. Die Proxy-Klasse ist hauptsächlich für die Vorverarbeitung von Nachrichten verantwortlich und Filtern für die Delegatklasse-Nachricht, Weiterleiten der Nachricht an die Delegatenklasse und anschließendes Verarbeiten der Nachricht usw. 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 können Agentenklassen in zwei Typen unterteilt werden.
Statischer Proxy: Von Programmierern erstellt oder automatisch von bestimmten Tools 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.
Erster Blick auf den statischen Proxy:
1. Count.java
package net.battier.dao; /** * 定义一个账户接口 * * @author Administrator * */ public interface Count { // 查看账户方法 public void queryCount(); // 修改账户方法 public void updateCount(); }
2. CountImpl.java
package net.battier.dao.impl; import net.battier.dao.Count; /** * 委托类(包含业务逻辑) * * @author Administrator * */ public class CountImpl implements Count { @Override public void queryCount() { System.out.println("查看账户方法..."); } @Override public void updateCount() { System.out.println("修改账户方法..."); } } 、CountProxy.java package net.battier.dao.impl; import net.battier.dao.Count; /** * 这是一个代理类(增强CountImpl实现类) * * @author Administrator * */ public class CountProxy implements Count { private CountImpl countImpl; /** * 覆盖默认构造器 * * @param countImpl */ public CountProxy(CountImpl countImpl) { this.countImpl = countImpl; } @Override public void queryCount() { System.out.println("事务处理之前"); // 调用委托类的方法; countImpl.queryCount(); System.out.println("事务处理之后"); } @Override public void updateCount() { System.out.println("事务处理之前"); // 调用委托类的方法; countImpl.updateCount(); System.out.println("事务处理之后"); } }
3. TestCount.java
package net.battier.test; import net.battier.dao.impl.CountImpl; import net.battier.dao.impl.CountProxy; /** *测试Count类 * * @author Administrator * */ public class 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 Proxys generiert alle Proxys Mit Ausnahme der aufgerufenen Methode sind alle anderen Vorgänge gleich, daher muss der Code zu diesem Zeitpunkt wiederholt werden. Der beste Weg, dieses Problem zu lösen, besteht darin, eine Proxy-Klasse zum Abschließen aller Proxy-Funktionen zu verwenden. In diesem Fall muss ein dynamischer Proxy zum Abschließen verwendet werden.
Werfen wir einen Blick auf den dynamischen Proxy:
Der dynamische JDK-Proxy enthält eine Klasse und eine Schnittstelle:
InvocationHandler-Schnittstelle:
public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }
Parameterbeschreibung:
Objekt-Proxy: verweist zum Proxy-Objekt.
Methodenmethode: die aufzurufende Methode
Objekt[]-Argumente: die beim Aufruf der Methode erforderlichen Parameter
Sie können sich die Unterklasse der InvocationHandler-Schnittstelle als die letzte Operationsklasse eines Proxys vorstellen. ersetzt ProxySubject .
Proxy-Klasse:
Die Proxy-Klasse ist eine auf Proxy-Operationen spezialisierte Klasse, die über diese Klasse dynamisch für eine oder mehrere Schnittstellen generiert werden kann:
öffentliches statisches Objekt newProxyInstance(ClassLoader-Loader, Class>[]-Schnittstellen,
InvocationHandler h)
🎜>Class> ;[]-Schnittstellen: alle Schnittstellen abrufen
InvocationHandler h: die Unterklasse abrufen Instanz der InvocationHandler-Schnittstelle
Ps: Klassenlader
Eine ClassLoader-Klasse ist in der newProxyInstance()-Methode in der Proxy-Klasse erforderlich. Instanzen von ClassLoader entsprechen tatsächlich Klassenladern. In Java gibt es drei Hauptklassenlader ;
Erweiterung ClassLoader: wird zum Laden erweiterter Klassen verwendet, die im Allgemeinen den Klassen im jrelibext-Verzeichnis entsprechen; ) lädt die durch den Klassenpfad angegebene Klasse, den am häufigsten verwendeten Lader.
Dynamischer Proxy
Im Gegensatz zur statischen Proxy-Klasse wird der Bytecode der dynamischen Proxy-Klasse dynamisch durch den Java-Reflektionsmechanismus generiert, wenn das Programm ausgeführt wird, ohne dass Programmierer dies tun müssen Schreiben Sie den Quellcode manuell. 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.
1. BookFacadeImpl.java
package net.battier.dao; public interface BookFacade { public void addBook(); }
Dynamischer Proxy von Cglib
Der dynamische Proxy-Mechanismus von JDK kann nur Proxy-Klassen implementieren, die keine Schnittstellen implementieren können. Der dynamische Proxy von JDK kann nicht implementiert werden. Das Prinzip besteht darin, eine Unterklasse für zu generieren die angegebene Zielklasse und überschreiben Sie die Methoden, um eine Erweiterung zu erreichen. Da jedoch Vererbung verwendet wird, kann die endgültige geänderte Klasse nicht als Proxy verwendet werden.package net.battier.dao.impl; import net.battier.dao.BookFacade; public class BookFacadeImpl implements BookFacade { @Override public void addBook() { System.out.println("增加图书方法。。。"); } } 、BookFacadeProxy.java package net.battier.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK动态代理代理类 * * @author student * */ public class BookFacadeProxy implements InvocationHandler { private Object target; /** * 绑定委托对象并返回一个代理类 * @param target * @return */ public Object bind(Object target) { this.target = target; //取得代理对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷) } @Override /** * 调用方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; System.out.println("事物开始"); //执行方法 result=method.invoke(target, args); System.out.println("事物结束"); return result; } }
package net.battier.test; import net.battier.dao.BookFacade; import net.battier.dao.impl.BookFacadeImpl; import net.battier.proxy.BookFacadeProxy; public class TestProxy { public static void main(String[] args) { BookFacadeProxy proxy = new BookFacadeProxy(); BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); bookProxy.addBook(); } }
3. BookFacadeProxy.java
package net.battier.dao; public interface BookFacade { public void addBook(); }
package net.battier.dao.impl; /** * 这个是没有实现接口的实现类 * * @author student * */ public class BookFacadeImpl1 { public void addBook() { System.out.println("增加图书的普通方法..."); } }