Fundamentals 8 min read

Understanding Java Proxy Pattern: Static, JDK Dynamic, and CGLIB Proxies

This article explains the proxy design pattern in Java, demonstrates how to create static proxies, uses JDK dynamic proxies with InvocationHandler, and shows how CGLIB can generate class‑based proxies, highlighting their implementations, usage examples, and limitations.

FunTester
FunTester
FunTester
Understanding Java Proxy Pattern: Static, JDK Dynamic, and CGLIB Proxies

The proxy pattern is a common software design pattern that provides a surrogate or placeholder for another object to control access to it, such as network connections, large objects in memory, files, or other resources.

First, a static proxy example is presented: an IUserProvider interface is defined, implemented by UserProviderImpl , and a logging proxy LogProxy implements the same interface, delegating calls to the real provider while adding simple log statements.

package com.fun.ztest.proxytest;

public interface IUserProvider {
    User getUser(int i);
}
package com.fun.ztest.proxytest;

public class LogProxy implements IUserProvider {
    private static Logger logger = LoggerFactory.getLogger(LogProxy.class);
    private IUserProvider userProvider;
    public LogProxy(IUserProvider userProvider) { this.userProvider = userProvider; }
    @Override
    public User getUser(int i) {
        logger.info("获取用户{}", i + EMPTY);
        return userProvider.getUser(i);
    }
}

The static proxy works but is tightly coupled to the IUserProvider interface, limiting reuse.

To address this, JDK dynamic proxies are introduced. The AutoLogProxy class implements InvocationHandler , intercepting method calls, logging them, and delegating to the underlying target object.

public class AutoLogProxy implements InvocationHandler {
    private static Logger logger = LoggerFactory.getLogger(AutoLogProxy.class);
    private final Object drive;
    public AutoLogProxy(Object invocationTarget) { this.drive = invocationTarget; }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        logger.warn("调用方法:{},参数:{}", method.getName(), Arrays.toString(args));
        return method.invoke(drive, args);
    }
}

Usage involves Proxy.newProxyInstance with the target object and the handler, allowing the proxy to be created at runtime for any interface.

IUserProvider userProvider = new UserProviderImpl();
IUserProvider provider = (IUserProvider) Proxy.newProxyInstance(
    IUserProvider.class.getClassLoader(),
    new Class[]{IUserProvider.class},
    new AutoLogProxy(userProvider)
);
provider.getUser(10);

Dynamic proxies, however, require an interface; they cannot proxy classes directly. For class‑based proxying, the CGLIB library is used.

A CGLIB example defines a concrete class CUser with methods fun and tester , and a CUserProxy that implements MethodInterceptor to log method invocations before delegating to the original method.

public class CUser extends SourceCode {
    public void fun() { output(DEFAULT_STRING); }
    public void tester() { output(DEFAULT_CHARSET.name()); }
}
public class CUserProxy implements MethodInterceptor {
    private static Logger logger = LoggerFactory.getLogger(CUserProxy.class);
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        logger.info("调用方法:{},参数:{}", method.getName(), Arrays.toString(args));
        proxy.invokeSuper(obj, args);
        return obj;
    }
}

Using CGLIB’s Enhancer , a proxy instance of CUser is created, and method calls are automatically logged.

CUserProxy proxy = new CUserProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CUser.class);
enhancer.setCallback(proxy);
CUser user = (CUser) enhancer.create();
user.fun();

The article concludes that the proxy pattern is powerful for adding cross‑cutting concerns without modifying existing code, and that dynamic proxies (JDK or CGLIB) provide reusable and flexible ways to implement such behavior.

design patternsJavaDynamic ProxyProxy PatternCglibJDK Proxy
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login 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.