Understanding JDK vs CGLib Dynamic Proxies in Java: Code, Differences, and Performance

This article explains how JDK and CGLib dynamic proxies work in Java, provides complete implementation examples, compares their mechanisms, usage scenarios in Spring, and discusses performance differences across JDK versions.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Understanding JDK vs CGLib Dynamic Proxies in Java: Code, Differences, and Performance

Last Friday during an Alibaba interview I was asked about the difference between JDK and CGLib dynamic proxies, so I gathered information and organized it here for reference.

JDK Dynamic Proxy Implementation

Dynamic proxies are widely used in Java (Spring AOP, Hibernate, testing mocks, RPC, annotation processing). The proxy relationship is determined at runtime. Below are the core code examples.

public interface IHelloService {
    void sayHello();
}

public class HelloServiceImpl implements IHelloService {
    @Override
    public void sayHello() {
        System.out.println("Jdk say Hello");
    }
}

public class JdkDynamicProxy 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 proxyObject, Method method, Object[] args) throws Throwable {
        System.out.println("JdkDynamicProxy, " + method.getName() + " method, before execution");
        return method.invoke(this.targetObject, args);
    }
}

@Test
public void jdkDynamicProxyPatternTest() {
    IHelloService helloService = new HelloServiceImpl();
    IHelloService proxySubject = (IHelloService) new JdkDynamicProxy().newProxyInstance(helloService);
    proxySubject.sayHello();
}

The Proxy.newProxyInstance method creates a proxy object at runtime using the specified class loader, interfaces, and an InvocationHandler. All interface method calls are forwarded to invoke, where additional logic (logging, security checks, etc.) can be inserted. Note that methods inherited from Object such as hashCode, equals, and toString are also forwarded.

The JDK proxy creation involves three steps: define an interface, implement the interface, and create an InvocationHandler that forwards calls.

CGLib Dynamic Proxy Implementation

When the target class does not implement any interface, CGLib can generate a subclass proxy.

public class HelloService {
    public void sayHello() {
        System.out.println("Cglib Say Hello");
    }
}

public class CglibDynamicProxy implements MethodInterceptor {
    private Object target;

    public CglibDynamicProxy(Object target) {
        this.target = target;
    }

    public Object newProxyInstance() {
        Enhancer en = new Enhancer();
        en.setSuperclass(target.getClass());
        en.setCallback(this);
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CglibDynamicProxy, " + method.getName() + " method, before execution");
        Object returnValue = method.invoke(target, args);
        System.out.println("CglibDynamicProxy, " + method.getName() + " method, after execution");
        return returnValue;
    }
}

@Test
public void cglibDynamicProxyPatternTest() {
    HelloService cglibProxySubject = (HelloService) new CglibDynamicProxy(new HelloService()).newProxyInstance();
    cglibProxySubject.sayHello();
}

CGLib uses Enhancer to generate a subclass of the target class; all non‑final methods are intercepted by MethodInterceptor.intercept. Like JDK proxies, custom logic can be added before or after method execution. CGLib also proxies methods inherited from Object (except final methods such as getClass).

Analysis and Comparison

Since Java 1.3, dynamic proxy support has been part of the JDK. JDK proxies rely on java.lang.reflect.Proxy and InvocationHandler, and can only proxy interfaces. CGLib (Code Generation Library) builds on ASM to modify bytecode and create a subclass, allowing proxying of concrete classes but failing for final classes.

Key differences:

JDK proxy: interface‑based, cannot proxy classes without interfaces.

CGLib proxy: subclass‑based, works for concrete classes but cannot proxy final methods.

Performance: on JDK 1.6/1.7 JDK proxies were slower than CGLib; on JDK 1.8 JDK proxies became faster, though the gap is not as large as some benchmarks claim.

Spring usage: Spring defaults to JDK proxies when the bean implements an interface; otherwise it forces CGLib.

Understanding these mechanisms helps choose the appropriate proxy strategy and avoid common pitfalls when using Spring AOP.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performanceDynamic ProxycglibJDK Proxyspring-aop
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.