This week we’ll continue our exploration of design patterns and look at another structural pattern, the Proxy pattern.
The Gang of Four book has a very simple definition for the Proxy pattern:
“Provide a surrogate or placeholder for another object to control access to it.”
Understanding the Proxy Pattern
A proxy is a stand-in for something else. If we can’t attend a shareholder or club AGM, we can appoint a proxy who will vote in our place.
An everyday IT example is a cache for a web server. If a client requests the same page multiple times, the cache will just store the first request in memory, and return that page, instead of downloading the same file over and over again.
As programmers, we use proxies to stand-in for remote objects, or for objects that need some controlled access. A proxy stands-in for the target or service object. The proxy acts just like the target object, and controls access to it. The proxy class implements the same interface as the target object and delegates the actual work to the target object. However, the proxy can execute code before and/or after the target object’s method is called.
There are a number of reasons we’d like to do this:
- We’d like to delay creating and initializing the target object until we actually need it. This is known as lazy loading. or lazy instantiation. We do this when the target object is a heavyweight object that we don’t want to be loaded in memory all the time, but only when we use it.
- We’d like to execute some code before and/or after calling the real object. This could be code for transaction management, security access, caching, logging, smart reference counting, performing additional checks on arguments, or any other common business rules that cut across many different classes.
- We’d like to access a service on a remote server. The local proxy will then handle all of the low-level network connections and handshaking, and pass the client request to the remote service.
Dynamic Proxies
Java SE provides a mechanism called dynamic proxies, which allows us to create a proxy for a list of interfaces. We can set up a proxy at runtime instead of at compile time. It does require us to create an object that subclasses InvocationHandler
. This object will act as the go-between from the caller to the objects being proxied. The InvocationHandler
acts as the proxy.
Here’s how it works: a client requests a service object from a factory or other creational mechanism. The client then gets a proxy object that stands in for, and pass control to, the service object. The proxy object must implement the same interface as the one that was requested, so the proxy can be assigned to a variable of the correct type.
Dynamic proxies are built into the standard JDK, and no additional API dependencies are needed. They have been around since Java 1.3, and can be found in the java.lang.reflect
package.
Proxy Pattern: Design Example
Revisiting our first person shooter game as usual, we’ve already created mechanised fighting units, like self-driving armoured vehicles and autonomous fighting robots. We can command them to fight and move towards specific targets.
Interface Code
We had previously created a FightingUnit
interface with a fight()
method and some methods for movement:
public interface FightingUnit { public void fight(); public void turn(int degrees); public void advance(); public void retreat(); }
We had also created MechanisedFightingRobot
and MechanisedFightingVehicle
concrete classes. A simple stub class follows:
public class MechanisedFightingRobot implements FightingUnit { public void fight() { System.out.println("Robot fighting!"); } public void turn(int degrees) { System.out.println("Robot turning through " + degrees + " degrees"); } public void advance() { System.out.println("Robot advancing..."); } public void retreat() { System.out.println("Robot retreating..."); } @Override public String toString() { return getClass().getName(); } } // end of class
Let’s say that we want to log everything that a FightingUnit
did. We definitely wouldn’t want to go back and add the logging code to every method of every concrete class, because that would give us infinite headaches with the possibility of missing a method or breaking other existing code.
InvocationHandler Code
What we will rather do is create a proxy class that wraps around our FightingUnit
and intercepts the method calls. We can insert the logging code in the intercepting code of the proxy.
First we’ll create a handler class that implements the InvocationHandler
interface. This has a single invoke()
method that is called whenever a method on the proxy object is called.
The invoke()
method takes three parameters:
- A reference to the proxy object on which the method has been called.
- A reference to the actual invoked method.
- The arguments that were passed to the method (as an array).
Here we are just going to print out the method name and the arguments passed to it. Then we will delegate the method call to the target object that has been passed to the LoggingHandler
constructor.
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; public class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(String.format("Calling method %s with args: %s", method.getName(), Arrays.toString(args))); return method.invoke(target, args); } }
Dynamic Proxy Code
Dynamic proxies let us create a implementation for a specific interface at runtime. Method calls on this generated proxy are delegated to the specified InvocationHandler
.
We create a new proxy object with Proxy.newProxyInstance()
. This method takes three arguments:
- The
ClassLoader
that should be used. - A list of interfaces that the proxy should implement (here our
FightingUnit
). - The
InvocationHandler
implementation to dispatch method invocations to (ourLoggingHandler
).
We’ve already created our LoggingHandler
, so we’ll use it in the following code snippet to create and test the dynamic proxy:
import java.lang.reflect.Proxy; public class ProxyTester { public static void main (String args[]) { FightingUnit robot = new MechanisedFightingRobot(); System.out.println(robot); // creating the dynamic proxy FightingUnit proxy = (FightingUnit) Proxy.newProxyInstance ( FightingUnit.class.getClassLoader(), new Class[] { FightingUnit.class }, new LoggingHandler(robot) ); // call the robot methods directly and then through the proxy test(robot); test(proxy); } public static void test(FightingUnit unit) { unit.fight(); unit.turn(90); unit.advance(); unit.retreat(); } }
Dynamic proxies support reusability by separating the proxy creation (with Proxy.newProxyInstance()
) and the proxy logic (the LoggingHandler
). We didn’t refer to the FightingUnit
interface at all in the LoggingHandler
. We passed an Object
reference into the constructor, which allows us to reuse the LoggingHandler
for any other interface.
Obviously we as programmers don’t want to do this boilerplate code every time we’d like to create a dynamic proxy. In most frameworks such as Spring, proxies are generated automatically from annotations or XML configuration. This code would be relegated to an annotation processor.
Conclusion
The Proxy Pattern is very powerful. It allows us to add functionality without modifying the target implementation or the client. This includes access to remote objects, transaction management, lazy loading, and transparently adding extra behaviour such as logging and caching.
What’s next
In the weeks ahead, we’ll continue examining the last remaining GoF design patterns. Stay tuned and keep learning!
As always, please share your comments and questions.