Java Dynamic Proxy Mechanism and Design Pattern Overview
This article explains the Proxy design pattern, details Java's dynamic proxy classes and interfaces from JDK 1.6 source, walks through the step‑by‑step creation process, presents a complete demo implementation, and analyzes the underlying Proxy class generation and InvocationHandler mechanisms.
The Proxy pattern provides a surrogate object that controls access to a real subject, allowing preprocessing, filtering, and post‑processing of method calls. In Java, the dynamic proxy mechanism implements this pattern using the java.lang.reflect.Proxy class and the InvocationHandler interface.
Key JDK classes and interfaces
public static InvocationHandler getInvocationHandler(Object proxy) public static Class getProxyClass(ClassLoader loader, Class ... interfaces) public static boolean isProxyClass(Class cl) public static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler h)
The InvocationHandler interface defines the method Object invoke(Object proxy, Method method, Object[] args) throws Throwable which receives the proxy instance, the invoked method, and its arguments, allowing custom handling before delegating to the real object.
Dynamic proxy creation steps
Implement a custom InvocationHandler that holds a reference to the real target.
Call Proxy.newProxyInstance with a class loader, the target interfaces, and the handler; this method internally performs security checks, looks up or generates a proxy class, obtains its constructor, and instantiates the proxy.
The proxy class name follows the pattern $ProxyN , where N is a unique number.
The generated class bytecode is produced by ProxyGenerator.generateProxyClass and defined at runtime.
Demo implementation
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HelloServiceProxy implements InvocationHandler {
private Object target;
public Object bind(Object target, Class[] interfaces) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.err.println("############我是JDK动态代理################");
System.err.println("我准备说hello。");
Object result = method.invoke(target, args);
System.err.println("我说过hello了");
return result;
}
}
public class ProxyTest {
public static void main(String[] args) {
HelloServiceProxy proxy = new HelloServiceProxy();
HelloService service = new HelloServiceImpl();
service = (HelloService) proxy.bind(service, new Class[]{HelloService.class});
service.sayHello("张三");
}
}The output demonstrates the pre‑ and post‑processing around the actual method call.
Internal workings of Proxy
The static method newProxyInstance validates the handler, obtains the proxy class via getProxyClass0 , retrieves the appropriate constructor, and creates the instance, handling security managers when necessary.
private static Map loaderToCache = new WeakHashMap(); private static Object pendingGenerationMarker = new Object(); private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); protected InvocationHandler h;
public static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler h) throws IllegalArgumentException { ... }
The getProxyClass0 method performs four main steps: security checks on the interfaces, cache lookup/creation per class loader, synchronization to avoid duplicate generation, and finally bytecode generation using ProxyGenerator . The generated class is defined with a unique name and stored in a weak reference cache.
public static byte[] generateProxyClass(final String name, Class[] interfaces) { ... }
After generation, the proxy class is cached; if generation fails, the placeholder is removed and waiting threads are notified.
Conclusion
Java's dynamic proxy, built on reflection and bytecode generation, is the foundation for many frameworks such as Spring AOP and MyBatis plugins, enabling flexible pre‑ and post‑processing of method invocations.
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.