The Proxy Design Pattern: The Gatekeeper
Master the Proxy Pattern in Java. Learn how to control access to objects, implement lazy loading, and add security layers.
Moshiour Rahman
Advertisement
The Problem: Expensive Objects
Imagine you have a HighResolutionImage class. Loading it consumes 500MB of RAM and takes 5 seconds because it downloads a 4K image from a server.
If your webpage has a list of 100 images, and you instantiate all HighResolutionImage objects at startup, your app will crash or freeze.
Most users won’t even scroll down to see them all. Why load them?
The Solution: The Proxy Pattern
The Proxy Pattern provides a surrogate or placeholder for another object to control access to it. It allows you to perform magic (security check, lazy loading, logging) before the real object is called.
Real-Life Analogy: A Credit Card 💳
- Real Money (The Real Subject): Using cash requires having physical bills. It’s bulky and risky.
- Credit Card (The Proxy): It represents cash. When you swipe it, the bank checks if you have funds (Access Control) and then transfers the money later (Lazy Execution).
Visualizing the Pattern

Implementation
1. The Interface
Common interface so the client can treat Proxy and RealObject identically.
public interface Image {
void display();
}
2. The Real Object (Expensive)
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(); // Expensive operation happens at creation!
}
private void loadFromDisk() {
System.out.println("Loading " + filename + " (Taking 5 seconds...)");
try { Thread.sleep(500); } catch (Exception e) {}
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
}
3. The Proxy (Lazy Loader)
public class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
// Note: RealImage is NOT created here. It's cheap to make a Proxy.
}
@Override
public void display() {
// Lazy Loading Logic
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
Usage
// Fast! No loading happens yet.
Image image = new ProxyImage("4k_photo.jpg");
System.out.println("Image created. Nothing loaded yet.");
// Only NOW does it load from disk
image.display();
// Second call uses cached version
image.display();
In The Wild (Real World Examples)
1. Hibernate / JPA (Lazy Loading)
When you fetch a User from the database, Hibernate returns a Proxy for the List<Order>.
It doesn’t fetch the orders until you actually call user.getOrders().size().
2. Spring AOP (Aspect Oriented Programming)
When you add @Transactional to a method, Spring wraps your bean in a Proxy. The Proxy starts the transaction, calls your method, and then commits the transaction.
Cheat Sheet
| Feature | Details |
|---|---|
| Category | Structural |
| Problem Solved | Expensive object creation, Access Control, Security |
| Key implementation | if (realObj == null) realObj = new RealObj(); |
| Pros | Performance (Lazy Loading), Security (Check permissions in Proxy) |
| Cons | Adds complexity, hides the fact that a method call might be expensive |
Tips to Remember 🧠
- “The Gatekeeper”: A bodyguard or receptionist is a proxy. You have to go through them to see the CEO (Real Object).
- Lazy vs Eager: Use Proxy when you want “Lazy Initialization”.
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
The Visitor Design Pattern: Add Operations Without Modifying Classes
Master the Visitor Pattern in Java. Learn how to add new operations to object structures using double dispatch.
JavaThe Template Method Pattern: The Recipe for Success
Master the Template Method Pattern in Java. Learn how to define the skeleton of an algorithm in a superclass but let subclasses override specific steps.
JavaThe Strategy Design Pattern: Kill the If-Else Statements
Master the Strategy Pattern in Java. Learn how to replace complex if-else logic with interchangeable algorithms and follow the Open/Closed Principle.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.