Ein Dynamic Proxy ermöglicht es, das Verhalten von Methoden eines Objekts zur Laufzeit zu beeinflussen. So ist es möglich, Methoden um bestimmte Funktionen zu erweitern oder sogar Methoden zu deaktivieren. Die Anwendungsgebiete reichen von einfachen Logging-Funktionen, die nachträglich zu Methoden hinzugefügt werden, bis hin zu komplexen Berechtigungsprüfungen, die den Zugriff auf bestimmte Methoden regeln.
Allerdings muss die Verwendung eines Dynamic Proxies frühzeitig in der Systemarchitektur eingeplant werden, da die Methoden eines Objekts nicht mehr innerhalb des Programms direkt aufgerufen werden dürfen, sondern nur noch indirekt über ein spezielles Proxy-Objekt der Klasse java.lang.reflect.Proxy.
Methoden können mit Hilfe von Invocation-Handlern um bestimmte Funktionen erweitert werden. Ein Invocation Handler muss das Interface java.lang.reflect.InvocationHandler implementieren. In dem Interface ist genau eine Methode definiert, die Methode invoke(). Die Methode wird von dem Proxy-Objekt aufgerufen, bevor die eigentliche Methode des Zielobjekts aufgerufen wird. Innerhalb der Methode invoke() muss bzw. kann die Methode des Zielobjekts aufgerufen werden. Auf diese Weise ist es möglich vor und hinter dem Methodenaufruf eigene Programmlogik zu implementieren.
Die genaue Funktionsweise und Implementierung werde ich nun anhand eines Beispiels erläutern. Als erstes muss natürlich eine Klasse mit einer Methode implementiert werden, die später dynamisch erweitert werden soll. Zusätzlich zu der Klasse muss allerdings auch ein Interface definiert werden, in dem alle Methoden deklariert sind, die durch den Dynamic Proxy erweiterbar sein sollen. Das ist mit Sicherheit der grösste Nachteil bei der Verwendung des Dynamic Proxies.
Hello und HelloImpl
Hier also nun das Interface Hello, in dem die Methode sayHello() deklariert ist, die dynamisch erweiterbar sein soll.
public interface Hello {
public String sayHello(String name);
}
Nun kann in einer eigenen Klasse das Standardverhalten des Interfaces implementiert werden.
public class HelloImpl implements Hello {
public String sayHello(String name) {
System.out.println("Hello " + name + "!");
return "Hello " + name + "!";
}
}
InvocationHandler
Als nächstes folgt die Implementierung des Invocation Handlers. Zur Erinnerung, der Invocation Handler wird von dem Proxy-Objekt aufgerufen. In dem Interface InvocationHandler muss die Methode invoke() implementiert werden. Die Syntax der Methode ist:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {}
Der Parameter proxy gibt hier die Proxy-Instance an, mit der der Invocation Handler aufgerufen wurde und nicht das Zielobjekt, dessen Methoden erweitert werden sollen. Folglich muss im Invocation Handler das Zielobjekt gespeichert werden (z.B. im Konstruktor). Die Methode method und deren Argumente args müssen dann entsprechend auf dem Zielobjekt mittels method.invoke() aufgerufen werden.
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogHandler implements InvocationHandler {
private Object object;
public LogHandler(Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoking method " + method.getName());
Object result = method.invoke(this.object, args);
System.out.println("Done.");
return result;
}
}
Proxy
Über den Aufruf Proxy.newProxyInstance() wird das Proxy-Objekt erzeugt, das den Invocation Handler mit der eigenen Klasse verbindet. Als Parameter muss der ClassLoader und das Interface angegeben werden, in dem die Methoden definiert sind, die dynamisch erweiterbar sind.
import java.lang.reflect.Proxy;
public class HelloDemo {
public static void main(String[] args) {
HelloImpl helloImpl = new HelloImpl();
ClassLoader loader = helloImpl.getClass().getClassLoader();
Class[] interfaces = new Class[] { Hello.class };
LogHandler logHandler = new LogHandler(helloImpl);
Hello helloProxy = (Hello) Proxy.newProxyInstance(loader, interfaces, logHandler);
helloProxy.sayHello("Chris");
}
}

![Validate my RSS feed [Valid RSS]](/templates/bitworld/images/valid-rss.png)
