Mastering Spring Dynamic Proxies: JDK vs CGLIB Explained
This article explains the concept of dynamic proxies, compares Spring's JDK‑based and CGLIB‑based proxy implementations with code examples, and shows how they power Spring AOP for cross‑cutting concerns such as transactions and logging.
Dynamic proxy is a runtime technique that generates proxy classes, allowing control over target objects without modifying them.
Spring uses dynamic proxies extensively for AOP, enabling cross‑cutting concerns such as transaction management and logging.
Spring supports two main proxy mechanisms: JDK dynamic proxy (interface‑based) and CGLIB proxy (subclass‑based).
JDK Dynamic Proxy
Works only for classes that implement interfaces. It requires an InvocationHandler implementation and the use of Proxy.newProxyInstance to create the proxy.
Steps:
Target class implements an interface.
Create an InvocationHandler with an invoke method.
Generate the proxy via Proxy.newProxyInstance.
public class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before method");
Object result = method.invoke(target, args);
System.out.println("after method");
return result;
}
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
DynamicProxy dynamicProxy = new DynamicProxy(realSubject);
Subject subject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
dynamicProxy);
subject.doSomething();
}
}
interface Subject {
void doSomething();
}
class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something.");
}
}CGLIB Dynamic Proxy
Based on subclassing, it can proxy any class, even those without interfaces, by generating bytecode at runtime using the CGLIB library.
public class UserService {
public void addUser(String name) {
System.out.println("add user: " + name);
}
}
public class UserServiceProxy implements MethodInterceptor {
private Object target;
public UserServiceProxy(Object target) {
this.target = target;
}
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("after method: " + method.getName());
return result;
}
}
public class Main {
public static void main(String[] args) {
UserService userService = new UserService();
UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
UserService proxy = (UserService) userServiceProxy.createProxy();
proxy.addUser("Tom");
}
}Spring automatically chooses the appropriate proxy type: if the target implements interfaces, it uses JDK dynamic proxy; otherwise it falls back to CGLIB.
These proxy mechanisms form the foundation of Spring AOP, allowing developers to weave additional behavior around business methods.
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.
Mike Chen's Internet Architecture
Over ten years of BAT architecture experience, shared generously!
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.
