Master Java Proxy: From Static to JDK Dynamic Proxy with Real Code
This article explains the proxy design pattern, shows how to implement static proxies in Java with concrete code examples, discusses their limitations, and then demonstrates JDK dynamic proxies using InvocationHandler and Proxy classes, including generated proxy class details.
Proxy Pattern Overview
The proxy pattern provides a surrogate object that controls access to a real subject, allowing additional behavior such as logging or access control without modifying the original class.
Roles in the Proxy Pattern
Subject : defines the common interface for both real and proxy objects.
RealSubject : the actual business logic implementation.
Proxy : holds a reference to a RealSubject and forwards calls, optionally adding extra processing.
Static Proxy Example
We define an interface Sell with methods sell() and ad(). Vendor implements this interface as the real subject, while Shop implements the same interface and delegates calls to a Vendor instance, allowing extra logic such as logging or permission checks.
/**
* 委托类和代理类都实现了Sell接口
*/
public interface Sell {
void sell();
void ad();
}
/**
* 供应商(真实主题)
*/
public class Vendor implements Sell {
@Override
public void sell() {
System.out.println("Shop sell goods");
}
@Override
public void ad() {
System.out.println("Shop advert goods");
}
}
/**
* 超市(代理)
*/
public class Shop implements Sell {
private Sell sell;
public Shop(Sell sell) { this.sell = sell; }
@Override
public void sell() {
System.out.println("代理类Shop,处理sell");
sell.sell();
}
@Override
public void ad() {
System.out.println("代理类Shop,处理ad");
sell.ad();
}
}
/**
* 静态代理测试
*/
public class StaticProxy {
public static void main(String[] args) {
Vendor vendor = new Vendor();
Sell sell = new Shop(vendor);
sell.ad();
sell.sell();
}
}Drawbacks of Static Proxy
When many classes need proxies, each requires a separate proxy class or a huge monolithic proxy, leading to code bloat.
Any change to the interface forces updates in both the real and proxy classes, making maintenance difficult.
Dynamic Proxy Introduction
Dynamic proxies are created at runtime, eliminating the need for hand‑written proxy classes. The JDK provides java.lang.reflect.Proxy and java.lang.reflect.InvocationHandler to generate proxy instances that implement specified interfaces.
JDK Dynamic Proxy Implementation
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
public class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) { this.target = target; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
private void before() {
System.out.println(String.format("log start time [%s] ", new Date()));
}
private void after() {
System.out.println(String.format("log end time [%s] ", new Date()));
}
}
import java.lang.reflect.Proxy;
/**
* 动态代理测试
*/
public class DynamicProxyMain {
public static void main(String[] args) {
LogHandler logHandler = new LogHandler(new Vendor());
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Sell sell = (Sell) Proxy.newProxyInstance(
Sell.class.getClassLoader(),
new Class[]{Sell.class},
logHandler);
sell.sell();
sell.ad();
}
}Running the program prints log messages before and after each method invocation, demonstrating how cross‑cutting concerns can be added without touching the original Vendor code.
Generated Proxy Class Details
When the system property sun.misc.ProxyGenerator.saveGeneratedFiles is set, the JDK writes the generated proxy class (e.g., $Proxy0.class) to disk. Decompiling it reveals a final class that extends Proxy and implements the target interface, with method dispatch delegated to the InvocationHandler.
package com.sun.proxy;
import com.choupangxia.proxy.Sell;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy implements Sell {
private static Method m1; // equals
private static Method m2; // toString
private static Method m3; // sell
private static Method m4; // ad
private static Method m0; // hashCode
public $Proxy0(InvocationHandler h) { super(h); }
public final void sell() { super.h.invoke(this, m3, null); }
public final void ad() { super.h.invoke(this, m4, null); }
// other Object methods omitted for brevity
static {
try {
m1 = Object.class.getMethod("equals", Object.class);
m2 = Object.class.getMethod("toString");
m3 = Sell.class.getMethod("sell");
m4 = Sell.class.getMethod("ad");
m0 = Object.class.getMethod("hashCode");
} catch (Exception e) { throw new RuntimeException(e); }
}
}Conclusion
The proxy pattern, especially when combined with JDK dynamic proxies, enables clean separation of cross‑cutting concerns such as logging, security, or transaction management. Understanding static and dynamic proxies lays a solid foundation for using higher‑level frameworks that rely on these mechanisms.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
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.
