Description / Meta Description
Learn the Proxy Design Pattern in Java with practical examples. Understand how Proxy controls access to objects, enables lazy loading, caching, security, remote calls, and how frameworks like Spring AOP, Hibernate, and microservices rely heavily on Proxy implementations.
Proxy Design Pattern in Java: Controlling Access to Objects Without Changing Their Behavior
In the previous article, we explored the Facade Pattern, which simplifies complex subsystems behind a clean interface.
Facade answers:
“How do I simplify complexity?”
Proxy answers a different question:
“How do I control access to an object?”
This pattern is everywhere in modern Java applications.
If you’ve worked with:
- Spring AOP
- Hibernate Lazy Loading
- Security Interceptors
- Remote Services
- Caching Layers
then you’ve already used Proxy—whether you realized it or not.
The Problem: Direct Access Isn’t Always Ideal
Consider a simple document service.
public interface DocumentService {
void viewDocument();
}
Implementation:
public class RealDocumentService
implements DocumentService {
@Override
public void viewDocument() {
System.out.println(
"Displaying Document");
}
}
Usage:
DocumentService service =
new RealDocumentService();
service.viewDocument();
Looks fine.
But what happens if we need:
- Authorization
- Logging
- Caching
- Rate Limiting
- Remote Access
- Lazy Loading
Do we modify RealDocumentService?
That quickly violates the Single Responsibility Principle.
What We Really Want
Instead of:
Client
│
▼
Real Service
We want:
Client
│
▼
Proxy
│
▼
Real Service
The proxy sits between client and target object.
It decides:
Allow?
Block?
Cache?
Log?
Load Later?
What is Proxy Pattern?
Proxy is a Structural Design Pattern that:
Provides a placeholder or surrogate for another object and controls access to it.
Think of a security guard.
Visitor
│
▼
Security Guard
│
▼
Building
Visitors don’t access the building directly.
The guard controls access.
The guard is the Proxy.
Architecture Diagram
Client
│
▼
DocumentService
▲
│
DocumentProxy
│
▼
RealDocumentService
Notice:
The proxy implements the same interface.
The client often cannot distinguish between proxy and real object.
Step 1: Define Service Interface
public interface DocumentService {
void viewDocument();
}
Step 2: Create Real Service
public class RealDocumentService
implements DocumentService {
@Override
public void viewDocument() {
System.out.println(
"Displaying Document");
}
}
Step 3: Create Proxy
public class DocumentProxy
implements DocumentService {
private RealDocumentService service =
new RealDocumentService();
@Override
public void viewDocument() {
System.out.println(
"Checking Authorization");
service.viewDocument();
}
}
Step 4: Client Usage
DocumentService service =
new DocumentProxy();
service.viewDocument();
Output:
Checking Authorization
Displaying Document
The proxy adds behavior without modifying the real service.
Why Proxy Works
Without Proxy:
Client
│
▼
Real Service
With Proxy:
Client
│
▼
Proxy
│
▼
Real Service
The proxy becomes a controlled gateway.
Common Types of Proxy
GoF describes Proxy broadly, but in modern systems several variations have emerged.
1. Virtual Proxy (Lazy Loading)
One of the most important types.
Suppose loading a large image takes:
5 Seconds
500 MB Memory
Loading it immediately may be wasteful.
Instead:
Image Proxy
│
▼
Load Only When Needed
Example:
public class ImageProxy
implements Image {
private RealImage image;
@Override
public void display() {
if(image == null) {
image =
new RealImage();
}
image.display();
}
}
Object creation becomes lazy.
Hibernate Lazy Loading
One of the most famous Proxy examples.
Suppose:
@Entity
public class Customer {
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
}
Query:
Customer customer =
repository.findById(id);
Hibernate does NOT immediately load orders.
Instead:
Customer Proxy
│
▼
Orders Not Loaded Yet
When:
customer.getOrders();
is called,
Hibernate loads the data.
This is Virtual Proxy.
2. Protection Proxy (Security)
Controls access based on permissions.
Example:
public class AdminProxy
implements DocumentService {
private DocumentService service;
public AdminProxy(
DocumentService service) {
this.service = service;
}
@Override
public void viewDocument() {
if(isAdmin()) {
service.viewDocument();
}
else {
throw new SecurityException(
"Access Denied");
}
}
}
Used heavily in:
- Spring Security
- API Gateways
- Authorization Layers
3. Caching Proxy
Avoid repeated expensive operations.
Example:
Database Query
↓
Cache Result
↓
Return Cached Data
Example:
public class ProductProxy
implements ProductService {
private Map<Integer, Product>
cache = new HashMap<>();
}
Benefits:
- Reduced DB calls
- Faster responses
- Better scalability
4. Remote Proxy
Represents objects located elsewhere.
Example:
Application
│
▼
Proxy
│
▼
Remote Service
Client thinks it is calling:
userService.getUser();
Reality:
HTTP Call
Network
Remote Server
This concept appears in:
- RMI
- SOAP
- REST Clients
- gRPC
Spring AOP: Proxy Everywhere
One of the best real-world examples.
Suppose:
@Transactional
public void saveOrder() {
}
Looks simple.
But Spring actually creates:
OrderService Proxy
│
▼
Real OrderService
Proxy adds:
- Transaction Begin
- Transaction Commit
- Rollback
- Exception Handling
Without modifying your code.
Spring Security Example
@PreAuthorize(
"hasRole('ADMIN')")
public void deleteUser() {
}
Spring creates a proxy.
Execution:
Client
│
▼
Security Proxy
│
▼
Target Method
Authorization occurs before execution.
Caching Example
Spring Cache:
@Cacheable("users")
public User getUser(Long id) {
}
Behind the scenes:
Cache Proxy
│
├── Cache Hit
│ ↓
│ Return Data
│
└── Cache Miss
↓
Execute Method
Again, proxy behavior.
Proxy vs Decorator
This is a common interview question.
Both wrap objects.
Both implement the same interface.
Yet intentions differ.
Decorator
Goal:
Add Behavior
Example:
Email
↓
Logging
↓
Encryption
Proxy
Goal:
Control Access
Example:
Security
Caching
Lazy Loading
Remote Calls
Proxy vs Adapter
Adapter
Purpose:
Make Interfaces Compatible
Example:
pay()
↓
makePayment()
Proxy
Purpose:
Control Access
Same interface.
Different behavior.
Proxy vs Facade
Facade
Goal:
Hide Complexity
Proxy
Goal:
Control Access
Facade simplifies.
Proxy protects or optimizes.
Benefits of Proxy Pattern
1. Security
Centralized authorization.
2. Lazy Loading
Objects created only when required.
3. Performance Optimization
Caching reduces expensive operations.
4. Remote Access Transparency
Client doesn’t know service is remote.
5. Logging and Monitoring
Interception becomes easy.
Common Mistakes
Mistake 1: Business Logic in Proxy
Proxy should control access.
Not become the business service.
Mistake 2: Excessive Proxy Chains
Proxy
↓
Proxy
↓
Proxy
↓
Proxy
Debugging becomes difficult.
Mistake 3: Confusing Proxy with Decorator
Remember:
Decorator
→ Enhance
Proxy
→ Control
When Should You Use Proxy?
Use Proxy when:
✔ Security is required
✔ Lazy loading is beneficial
✔ Caching improves performance
✔ Remote services are involved
✔ Monitoring and interception are needed
Avoid Proxy when:
❌ Direct access is acceptable
❌ Simpler solutions exist
❌ Additional abstraction adds no value
Structural Patterns Covered So Far
| Pattern | Purpose |
|---|---|
| Adapter | Translate interfaces |
| Decorator | Add behavior |
| Facade | Simplify complexity |
| Proxy | Control access |
Think of them like this:
Adapter
→ Translate
Decorator
→ Enhance
Facade
→ Simplify
Proxy
→ Control
Final Thoughts
The Proxy Pattern solves an extremely common architectural challenge:
How do we add security, caching, lazy loading, remote communication, or monitoring without modifying existing business logic?
By placing a controlled layer between clients and real objects, Proxy enables:
- Better security
- Improved performance
- Lazy initialization
- Transparent remote access
- Framework-level magic
This is why Proxy sits at the heart of:
- Spring AOP
- Spring Transactions
- Spring Security
- Hibernate Lazy Loading
- Caching Frameworks
- Microservice Clients
In the next article, we’ll continue our Structural Design Pattern journey with:
Composite Pattern — Treating Individual Objects and Groups of Objects Uniformly
You’ll learn how file systems, organization hierarchies, menu structures, and UI component trees rely heavily on Composite Pattern principles.