Understanding Static and Dynamic Proxy Patterns in Java
This article explains the concept of proxy patterns, compares static and dynamic proxies in Java, provides detailed code examples for each, and discusses their advantages, disadvantages, and implementation steps, helping developers choose the appropriate proxy technique for their projects.
1. Proxy Concept
A proxy provides a surrogate for a target object, controlling access and allowing pre‑processing, request delegation, and post‑processing while sharing a common interface with the real subject.
Proxies can be classified as static or dynamic depending on when the proxy class is generated.
2. Static Proxy
In a static proxy, the proxy class source code is written or generated before program execution and compiled into bytecode, so the relationship between proxy and delegate is fixed at compile time.
Typical static proxy components include:
/**
* Proxy interface. Handles tasks with a given name.
*/
public interface Subject {
void dealTask(String taskName);
}
/**
* Real subject that actually executes the task.
*/
public class RealSubject implements Subject {
@Override
public void dealTask(String taskName) {
System.out.println("Executing task: " + taskName);
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
/**
* Static proxy that records execution time.
*/
public class ProxySubject implements Subject {
private Subject delegate;
public ProxySubject(Subject delegate) { this.delegate = delegate; }
@Override
public void dealTask(String taskName) {
long stime = System.currentTimeMillis();
delegate.dealTask(taskName);
long ftime = System.currentTimeMillis();
System.out.println("Task took " + (ftime - stime) + " ms");
}
}
public class SubjectStaticFactory {
public static Subject getInstance() {
return new ProxySubject(new RealSubject());
}
}
public class Client1 {
public static void main(String[] args) {
Subject proxy = SubjectStaticFactory.getInstance();
proxy.dealTask("DBQueryTask");
}
}Advantages: business logic stays clean and reusable. Disadvantages: each method requires a proxy, and any interface change forces updates to all proxy classes.
3. Dynamic Proxy
Dynamic proxies are created at runtime using the reflection API; the JVM generates the proxy class bytecode on the fly, so no pre‑compiled proxy class is needed.
Key Java APIs:
// java.lang.reflect.Proxy static methods
static InvocationHandler getInvocationHandler(Object proxy);
static Class getProxyClass(ClassLoader loader, Class[] interfaces);
static boolean isProxyClass(Class cl);
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h);InvocationHandler interface defines the central Object invoke(Object proxy, Method method, Object[] args) method that dispatches calls to the real subject.
Implementation steps:
Create a class that implements InvocationHandler and holds a reference to the delegate.
Obtain the proxy class via Proxy.getProxyClass or directly via Proxy.newProxyInstance .
Instantiate the proxy using reflection or the convenience method.
public class SubjectInvocationHandler implements InvocationHandler {
private Object delegate;
public SubjectInvocationHandler(Object delegate) { this.delegate = delegate; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long stime = System.currentTimeMillis();
method.invoke(delegate, args);
long ftime = System.currentTimeMillis();
System.out.println("Task took " + (ftime - stime) + " ms");
return null;
}
}
public class DynProxyFactory {
public static Subject getInstance() {
Subject delegate = new RealSubject();
InvocationHandler handler = new SubjectInvocationHandler(delegate);
return (Subject) Proxy.newProxyInstance(
delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),
handler);
}
}
public class Client {
public static void main(String[] args) {
Subject proxy = DynProxyFactory.getInstance();
proxy.dealTask("DBQueryTask");
}
}Characteristics of generated proxy classes: placed in the default package (or the target interface's package), marked public final , named $ProxyN , and inherit from java.lang.reflect.Proxy while implementing the proxied interfaces.
Advantages: a single invoke method handles all interface methods, enabling flexible cross‑cutting concerns similar to AOP. Disadvantages: can only proxy interfaces, not concrete classes, due to Java's single‑inheritance limitation.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.