Your Guide to Design Patterns – Proxy Pattern

Design Pattern - Proxy Pattern

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 (our LoggingHandler).

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.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.