Proxy Pattern in Java – Control Access and Add Behavior Without Changing Real Objects

Illustration for Proxy Pattern in Java – Control Access and Add Behavior Without Changing Real Objects
By Last updated:

Introduction

The Proxy Pattern is a structural design pattern that provides a substitute or placeholder for another object, to control access, defer creation, add security, or log interactions.

Why Proxy Pattern Matters

In real-world Java apps, especially enterprise-scale, you often want to control access to a resource-heavy or remote object. The Proxy Pattern lets you wrap a real object with a helper or controller that enhances or protects it without altering its implementation.


Core Intent and Participants

  • Intent: Provide a surrogate or placeholder for another object to control access to it.

Participants

  • Subject: Common interface for RealSubject and Proxy.
  • RealSubject: The actual object that does the work.
  • Proxy: Controls access to the RealSubject.

UML Diagram (Text)

+-----------+        +-------------+        +-------------+
|  Client   | -----> |   Proxy     | -----> | RealSubject |
+-----------+        +-------------+        +-------------+
                          ^
                          |
                    +-----------+
                    |  Subject  |
                    +-----------+

Real-World Use Cases

  • Virtual proxy: Delay object creation until needed (e.g., lazy-loaded images)
  • Remote proxy: Represent remote service (e.g., RMI)
  • Protection proxy: Control user permissions
  • Smart proxy: Add logging, metrics, caching, transactions

Java Implementation Strategy

Example: Internet Access with Proxy

Step 1: Subject Interface

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

Step 2: Real Subject

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

Step 3: Proxy

import java.util.ArrayList;
import java.util.List;

public class ProxyInternet implements Internet {
    private Internet realInternet = new RealInternet();
    private static List<String> bannedSites;

    static {
        bannedSites = new ArrayList<>();
        bannedSites.add("example.com");
        bannedSites.add("blocked.com");
    }

    public void connectTo(String serverHost) throws Exception {
        if (bannedSites.contains(serverHost.toLowerCase())) {
            throw new Exception("Access Denied to " + serverHost);
        }
        realInternet.connectTo(serverHost);
    }
}

Step 4: Client Code

public class ProxyDemo {
    public static void main(String[] args) {
        Internet internet = new ProxyInternet();
        try {
            internet.connectTo("geeksforgeeks.org");
            internet.connectTo("example.com");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

✅ The proxy controls access and logs or blocks requests transparently.


Pros and Cons

✅ Pros

  • Adds functionality without modifying real object
  • Useful for lazy loading and access control
  • Reduces resource consumption and improves performance

❌ Cons

  • Extra layer of indirection increases complexity
  • Can introduce tight coupling between proxy and real subject
  • Not always transparent—client may need proxy awareness

Anti-Patterns and Misuse

  • Using Proxy for every object (overhead with no value)
  • Adding unrelated behavior (violating SRP)
  • Creating too many proxy types (violating DRY)

Proxy vs Decorator vs Adapter

Pattern Purpose Real Object Access Behavior Change Common Use Case
Proxy Control access or enhance ✅ Yes Sometimes Security, remote, caching
Decorator Add behavior dynamically ✅ Yes ✅ Yes Formatting, logging, compression
Adapter Interface conversion ✅ Yes ❌ No Legacy code integration

Refactoring Legacy Code

Before

Internet internet = new RealInternet();
internet.connectTo("blocked.com"); // Allowed, no restriction

After (Using Proxy)

Internet internet = new ProxyInternet();
internet.connectTo("blocked.com"); // Now blocked by proxy

✅ Enhanced functionality without changing original class.


Best Practices

  • Keep proxies lightweight and focused on one responsibility
  • Use interface-based design to make swapping easy
  • Combine with caching, logging, or permission systems
  • Leverage Java Dynamic Proxy API for runtime proxies

Real-World Analogy

Think of a security guard at a gate. People can’t directly access a high-security room (RealSubject). The guard (Proxy) checks ID and grants/denies access based on rules. This is what the Proxy Pattern does in code.


Java Version Relevance

  • Java 8+: Use lambdas or functional interfaces in dynamic proxies
  • Java 11+: Proxy pattern used in REST clients like HttpClient
  • Java Reflection API: java.lang.reflect.Proxy supports dynamic proxies

Conclusion & Key Takeaways

  • Proxy Pattern controls access, adds logging, caching, or defers object loading.
  • Used heavily in security, network programming, remoting, and Spring AOP.
  • Keep proxy logic simple and cohesive.
  • Java supports both static and dynamic proxies via interfaces.

FAQ – Proxy Pattern in Java

1. What is the Proxy Pattern?

A structural pattern that provides a placeholder or controller to access another object.

2. When should I use a proxy?

For lazy loading, security, logging, caching, or remote access.

3. Is Proxy Pattern the same as Decorator?

No. Decorator adds behavior; Proxy controls access.

4. What types of proxies exist?

Virtual, Remote, Protection, Smart, and Cache proxies.

5. What is a dynamic proxy in Java?

A proxy created at runtime using reflection (java.lang.reflect.Proxy).

6. How does Spring use Proxy Pattern?

Spring AOP uses proxies for method interception and annotations.

7. Can a proxy be used without interfaces?

Yes, using CGLIB or subclassing, though interface-based proxies are preferred.

8. Is Proxy Pattern suitable for logging?

Yes. Smart proxies can log or measure execution time.

9. Does it affect performance?

Minimal overhead if used correctly. Improves performance via lazy loading.

10. Is Proxy testable?

Yes. You can mock or verify proxy behavior independently.