Fundamentals 14 min read

Understanding the Proxy Design Pattern in Java: Static, Dynamic, and CGLIB Implementations

This article explains the Proxy design pattern, covering its purpose, static, dynamic (JDK), and CGLIB implementations in Java, provides complete code examples, discusses advantages and disadvantages, and outlines typical use cases such as lazy initialization, access control, remote services, logging, and caching.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding the Proxy Design Pattern in Java: Static, Dynamic, and CGLIB Implementations

Basic Introduction

Proxy pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. It can be used for remote objects, expensive-to-create objects, or objects that need security control.

Problem

When a heavyweight object is needed only occasionally, creating it eagerly wastes resources; duplicating lazy‑initialization code across clients is error‑prone, especially when the original class is part of a third‑party library.

Solution

Introduce a proxy class that implements the same interface as the real service. The client works with the proxy, which creates the real object on demand and delegates all calls, allowing pre‑ and post‑processing such as logging, caching, or access checks.

Proxy Structure

Four participants: Service Interface, Service (real object), Proxy (holds a reference to Service and adds extra behavior), Client (uses the interface).

Static Proxy Example

public interface Internet {
    void connectTo(String serverHost) throws Exception;
}

public class RealInternet implements Internet {
    @Override
    public void connectTo(String serverHost) throws Exception {
        System.out.println("Connecting to " + serverHost);
    }
}

public class ProxyInternet implements Internet {
    private Internet internet;
    private static List
bannedSites;
    static {
        bannedSites = new ArrayList<>();
        bannedSites.add("bilibili.com");
        bannedSites.add("youtube.com");
        bannedSites.add("weibo.com");
        bannedSites.add("qq.com");
    }
    public ProxyInternet(Internet internet) {
        this.internet = internet;
    }
    @Override
    public void connectTo(String serverhost) throws Exception {
        if (bannedSites.contains(serverhost.toLowerCase())) {
            throw new Exception("Access Denied:" + serverhost);
        }
        internet.connectTo(serverhost);
    }
}

public class Client {
    public static void main(String[] args) {
        Internet internet = new ProxyInternet(new RealInternet());
        try {
            internet.connectTo("so.com");
            internet.connectTo("qq.com");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

Dynamic Proxy (JDK) Example

public class ProxyFactory {
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (bannedSites.contains(args[0].toString().toLowerCase())) {
                        throw new Exception("Access Denied:" + args[0]);
                    }
                    return method.invoke(target, args);
                }
            }
        );
    }
    private static List
bannedSites;
    static {
        bannedSites = new ArrayList<>();
        bannedSites.add("bilibili.com");
        bannedSites.add("youtube.com");
        bannedSites.add("weibo.com");
        bannedSites.add("qq.com");
    }
}

CGLIB Proxy Example

public class ProxyFactory implements MethodInterceptor {
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib proxy start");
        Object result = method.invoke(target, objects);
        System.out.println("cglib proxy end");
        return result;
    }
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

Typical Application Scenarios

Lazy initialization (virtual proxy)

Access control (protection proxy)

Remote service access (remote proxy)

Logging requests (logging proxy)

Caching results (cache proxy)

Smart reference for resource cleanup

Proxy Pattern in AOP

Spring AOP uses JDK dynamic proxies or CGLIB to create proxies for beans; AspectJ uses compile‑time static proxies. The choice is made by DefaultAopProxyFactory based on configuration.

References

https://refactoringguru.cn/design-patterns/proxy https://www.geeksforgeeks.org/proxy-design-pattern/

design patternsJavaAOPDynamic ProxyProxy PatternStatic ProxyCGLIB
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

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.