Implementing Dynamic Proxies in Java with JDK Proxy
Proxy patetrns allow indirect access to target objects, enabling additional functionality like access control and auditing. A real-world analogy would be a property agent representing a homeowner.
Static Proxy Limitations
Static proxies require both the proxy and target classes to implement the same interface. This creates several constraints:
- Each proxy class can only handle one target class
- Target classes must be known in advance
- Code reuse becomes difficult with multiple target classes
interface LegalProcess {
void execute();
}
class Defendant implements LegalProcess {
private String name;
public Defendant(String name) {
this.name = name;
}
@Override
public void execute() {
System.out.println(name + " states: I'm innocent");
}
}
class Attorney implements LegalProcess {
private Defendant client;
public Attorney(Defendant client) {
this.client = client;
}
@Override
public void execute() {
System.out.println("Attorney presents evidence: Video shows client was traveling");
System.out.println("Attorney concludes: Client couldn't have committed the crime");
client.execute();
}
}
Dynamic Proxy Advantages
JDK dynamic proxies overcome static proxy limitations by:
- Creating proxy objects at runtime
- Working with any interface implementation
- Allowing flexible method interception
interface MealActions {
void consumeFood(String item);
void consumeDrink();
}
class Individual implements MealActions {
private String name;
public Individual(String name) {
this.name = name;
}
@Override
public void consumeFood(String item) {
System.out.println(name + " is eating " + item);
}
@Override
public void consumeDrink() {
System.out.println(name + " is drinking tea");
}
}
public class ProxyDemo {
public static void main(String[] args) {
MealActions person = new Individual("John");
MealActions proxy = (MealActions) Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
(p, method, params) -> {
if (method.getName().equals("consumeFood")) {
System.out.println("Washing hands before meal");
Object result = method.invoke(person, params);
System.out.println("Cleaning dishes after meal");
return result;
}
return method.invoke(person, params);
}
);
proxy.consumeFood("sandwich");
}
}
Key characteristics of JDK dynamic proxies:
- Operate at interface level - require both interface and implementation
- Proxy objects can only be cast to interfaces, not concrete classes
- Only interface-defined methods can be intercepted
- Annotations are only readable from interface methods