Dynamic proxies (overview)
Proxy + InvocationHandler generate a stand-in object at runtime that funnels every interface call through one method — the basis of logging, transactions, and AOP.
What a dynamic proxy is
A dynamic proxy is an object the JVM generates at runtime that implements one or more interfaces you name, and routes *every* method call on those interfaces through a single handler. It lets you wrap cross-cutting behaviour — logging, timing, access checks, transactions — around any interface without writing a hand-coded wrapper class for each method. This is the machinery behind aspect-oriented programming and Spring's interface-based proxies.
Two pieces, both in java.lang.reflect:
- InvocationHandler — an interface with one method, invoke(Object proxy, Method method, Object[] args). Every call on the proxy lands here.
- Proxy.newProxyInstance(loader, interfaces, handler) — the factory that builds the proxy object.
Worked example — a logging proxy
Suppose we have an interface and a real implementation:
interface Greeter { String greet(String who); }
class RealGreeter implements Greeter {
public String greet(String who) { return "Hello, " + who; }
}
We wrap it so every call is logged, *without* editing RealGreeter:
import java.lang.reflect.*;
Greeter real = new RealGreeter();
Greeter proxy = (Greeter) Proxy.newProxyInstance(
real.getClass().getClassLoader(),
new Class<?>[] { Greeter.class },
new InvocationHandler() {
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
System.out.println("calling " + m.getName());
Object result = m.invoke(real, args); // delegate to the real object
System.out.println("returned " + result);
return result;
}
});
proxy.greet("world"); // prints: calling greet / returned Hello, world
How it runs: proxy is a brand-new class the JVM synthesised that implements Greeter. Calling proxy.greet("world") does not run any hand-written greet body — it calls the handler's invoke, passing the Method for greet and the args ["world"]. The handler logs, forwards the call to real with m.invoke(real, args), logs the result, and returns it. You could add the same logging to any interface this way, with zero per-method boilerplate.
Where it fits
Dynamic proxies are the reflection-powered glue under many frameworks, but they only work for interfaces (the proxy must be cast to an interface type, not a concrete class). For COMP 308 you need the *concept* and the shape of newProxyInstance + InvocationHandler.invoke, not heavy use — this is a LOW-relevance topic that rounds out the reflection picture.