Geschichte der Frage:
Das Dynamic Proxy Pattern erschien in Java 1.3 und ermöglichte die Implementierung von AOP, Protokollierung, Sicherheit und dynamischer Codegenerierung ohne manuelles Schreiben von Proxy-Klassen. Dies wurde in Spring, Hibernate und anderen Frameworks sehr populär.
Problem:
Manchmal ist es erforderlich, Funktionalität zu einem bereits bestehenden Interface hinzuzufügen oder das Verhalten von Methoden zur Laufzeit zu ändern, ohne den Quellcode zu ändern. Beispiel: Protokollierung jeder Methodenaufruf, Zugriffskontrolle, Profiling. Das Hauptproblem ist die Unmöglichkeit, dies "von Hand" für alle Klassen zu tun, insbesondere wenn es viele Klassen gibt oder sie dynamisch generiert werden.
Lösung:
Java bietet eine Standard-API im Paket java.lang.reflect zur Erstellung von Proxy-Objekten "on the fly" für beliebige Interfaces mittels Proxy.newProxyInstance. Es wird ein Objekt InvocationHandler implementiert, das jeden Methodenaufruf entgegennimmt und seine eigene Logik implementiert.
Beispielcode:
import java.lang.reflect.*; interface Service { void serve(); } class ServiceImpl implements Service { public void serve() { System.out.println("Serving..."); } } class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Calling " + method.getName()); return method.invoke(target, args); } } Service service = (Service) Proxy.newProxyInstance( Service.class.getClassLoader(), new Class[]{Service.class}, new LoggingHandler(new ServiceImpl())); service.serve();
Wesentliche Merkmale:
Kann man mit einem standardmäßigen dynamischen Proxy eine normale Klasse „einwickeln“, die keine Interfaces implementiert?
Nein. Dynamische Proxys funktionieren nur mit Interfaces. Für Klassen ist eine Bytecode-Manipulation (z.B. CGLIB) erforderlich.
Was passiert, wenn das Interface Methoden mit einem Rückgabetyp enthält, der nicht mit dem Rückgabewert aus InvocationHandler kompatibel ist?
Es wird eine ClassCastException ausgelöst, daher muss der Rückgabewert streng mit der Definition des Interfaces kompatibel sein.
Kann man einen dynamischen Proxy für finale Methoden verwenden?
Nein. Proxys funktionieren nur auf der Ebene der Interfaces, und da gibt es keine finalen Methoden. Finale Methoden können überhaupt nicht überschrieben werden.
Negativer Fall
Ein Entwickler versuchte, ein Audit-Logging über Proxy in Klassen ohne Interface zu integrieren.
Vorteile:
Nachteile:
Positiver Fall
Ein Vertrag wurde über ein Interface defniert, für das bereits ein Proxy-Wrap erstellt wurde.
Vorteile:
Nachteile: