Understanding the Proxy Pattern: Static vs Dynamic Proxy and AOP in Java
This article explains the proxy design pattern, compares static and dynamic proxy implementations in Java, demonstrates how to use Java reflection and InvocationHandler for dynamic proxies, and shows how these techniques enable AOP features such as logging and transaction handling.
Proxy
Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it.
It allows the client to interact with the proxy as if it were the real object, enabling additional behavior such as logging, security, or lazy loading.
Static Proxy
Static proxy classes are written manually or generated by tools before compilation. They implement the same interface as the target class and delegate calls while adding extra logic.
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser");
}
@Override
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser");
}
@Override
public String findUser(String userId) {
System.out.println("UserManagerImpl.findUser");
return "张三";
}
@Override
public void modifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.modifyUser");
}
}Proxy class that adds logging before and after each method call:
public class UserManagerImplProxy implements UserManager {
private UserManager userManager;
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
@Override
public void addUser(String userId, String userName) {
try {
System.out.println("start-->addUser()");
userManager.addUser(userId, userName);
System.out.println("success-->addUser()");
} catch (Exception e) {
System.out.println("error-->addUser()");
}
}
@Override
public void delUser(String userId) { userManager.delUser(userId); }
@Override
public String findUser(String userId) { userManager.findUser(userId); return "张三"; }
@Override
public void modifyUser(String userId, String userName) { userManager.modifyUser(userId, userName); }
}Client usage:
public class Client {
public static void main(String[] args) {
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("1111", "张三");
}
}Dynamic Proxy
Dynamic proxies are created at runtime using reflection, allowing a single proxy class to handle multiple interfaces.
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
} public class LogHandler implements InvocationHandler {
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start-->>");
for (Object arg : args) {
System.out.println(arg);
}
Object ret = null;
try {
System.out.println("start-->>");
ret = method.invoke(targetObject, args);
System.out.println("success-->>");
} catch (Exception e) {
e.printStackTrace();
System.out.println("error-->>");
throw e;
}
return ret;
}
}Client using dynamic proxy:
public class Client {
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
UserManager userManager = (UserManager) logHandler.newProxyInstance(new UserManagerImpl());
userManager.addUser("1111", "张三");
}
}Dynamic proxies centralize cross‑cutting concerns (logging, security, transactions) in the InvocationHandler, which is the core idea of Aspect‑Oriented Programming (AOP).
Summary
Both static and dynamic proxies achieve the same goal of controlling access to a target object, but dynamic proxies provide greater flexibility and reduce code duplication, making them suitable for implementing AOP concepts in Java applications.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
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.