Java Institute DreamsCity 2000
Welcome to DreamsCity
Return to Java Institute

USING DYNAMIC PROXIES TO
LAYER NEW FUNCTIONALITY
OVER EXISTING CODE

Dynamic proxies allow you to implement new interfaces at runtime 
by forwarding all calls to an InvocationHandler. This tip shows 
you how to use dynamic proxies to add new capabilities without 
modifying existing code.

Consider the following program. The program includes an interface
named Explorer. The interface models the movement of an "explorer" 
around a Cartesian grid. The explorer can travel in any compass 
direction, and can report its current location. The class 
ExplorerImpl is a simple implementation of the Explorer interface. 
It uses two integer values to track the explorer's progress around 
the grid. The TestExplorer class sends the explorer on 100 random 
steps, and then logs the explorer's position.  

    import java.lang.reflect.Method;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    interface Explorer {
        public int getX();
        public int getY();
        public void goNorth();
        public void goSouth();
        public void goEast();
        public void goWest();
    }
    
    class ExplorerImpl implements Explorer {
        private int x;
        private int y;
        public int getX() {return x;}
        public int getY() {return y;}
        public void goNorth() {y++;}
        public void goSouth() {y--;}
        public void goEast() {x++;}
        public void goWest() {x--;}
    }
    
    public class TestExplorer {
        
        public static void test(Explorer e) {
            for (int n=0; n<100; n++) {
                switch ((int)(Math.random() * 4)) {
                    case 0: e.goNorth(); break;
                    case 1: e.goSouth(); break;
                    case 2: e.goEast(); break;
                    case 3: e.goWest(); break;
                }
            }
            System.out.println("Explorer ended at " 
                                + e.getX() + "," + e.getY());
        }
        
        public static void main(String[] args) {
            Explorer e = new ExplorerImpl();
            test(e);
        }
    }    

Try running the TestExplorer class. You should get one line of 
output, similar to this:

Explorer ended at -2,8

Now, imagine that the requirements for the system change, and you 
need to log the explorer's movement at each step. Because the 
client programmed against an interface, this is straightforward; 
you could simply create a LoggedExplorer wrapper class that logs 
each method call before delegating to the original Explorer 
implementation. This is a nice solution because it does not require 
any changes to ExplorerImpl. Here's the new LoggingExplorer wrapper 
class: 

    class LoggingExplorer implements Explorer {
        Explorer realExplorer;
        public LoggingExplorer(Explorer realExplorer) {
            this.realExplorer = realExplorer;
        }
        public int getX() {
            return realExplorer.getX();
        }
        public int getY() {
            return realExplorer.getY();
        }
        public void goNorth() {
            System.out.println("goNorth");
            realExplorer.goNorth();     
        }
        public void goSouth() {
            System.out.println("goSouth");
            realExplorer.goSouth();     
        }
        public void goEast() {
            System.out.println("goEast");
            realExplorer.goEast();      
        }
        public void goWest() {
            System.out.println("goWest");
            realExplorer.goWest();      
        }
    }
    
The LoggingExplorer class delegates to an underlying realExplorer
interface, which allows you to add logging to any existing Explorer 
implementation. The only change clients of the Explorer interface
need to make is to construct the LoggingExplorer so that it wraps 
the Explorer interface. To do this, modify TestExplorer's main 
method as follows:

    public static void main(String[] args) {
        Explorer real = new ExplorerImpl();
        Explorer wrapper = new LoggingExplorer(real);
        test(wrapper);
    }

Now your output should be similar to

    goWest
    goNorth
    ...several of these...
    goWest
    goNorth
    Explorer ended at 2,2

By delegating to an underlying interface, you added a new layer of 
function without changing the ExplorerImpl code. And you did it 
with only a trivial change to the test client.  

The LoggingExplorer wrapper class is a good start to using 
delegation, but this "by-hand" approach has two major drawbacks. 
First, it's tedious. Each individual method of the Explorer 
interface must be reimplemented in the LoggingExplorer 
implementation. The second drawback is that the problem (that is, 
logging) is generic, but the solution is not. If you want to log 
some other interface, you need to write a separate wrapper class.

The Dynamic Proxy Class API can solve both of these problems.  

A dynamic proxy is a special class created at runtime by the 
Java(tm) virtual machine*. You can request a proxy class that 
implements any interface, or even a group of interfaces, by 
calling: 

    Proxy.newProxyInstance(ClassLoader classLoaderToUse,
                       Class[] interfacesToImplement,
                       InvocationHandler objToDelegateTo)

The JVM manufactures a new class that implements the interfaces you 
request, forwarding all calls to InvocationHandler's single method: 

    public Object invoke(Object proxy, Method meth, Object[] args)
              throws Throwable;

All you have to do is implement the invoke method in a class that 
implements the InvocationHandler interface. The Proxy class then 
forwards all calls to you.  

Let's make this work for the Explorer interface. Replace the 
LoggingExplorer wrapper class with the following Logger class.

    class Logger implements InvocationHandler {
        private Object delegate;
        public Logger(Object o) {
            delegate = o;
        }
        public Object invoke(Object proxy, Method meth, Object[] args) 
                            throws Throwable {
            System.out.println(meth.getName());        
            return meth.invoke(delegate, args);
        }
    }

This implementation of the invoke method can log any method call on 
any interface. It uses reflective invocation on the Method object 
to delegate to the real object. 

Now modify the TestExplorer main method as follows to create 
a dynamic proxy class: 

    public static void main(String[] args) {
        Explorer real = new ExplorerImpl();
        Explorer wrapper = (Explorer) Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[] {Explorer.class},
                new Logger(real));
        test(wrapper);
    }

The static method Proxy.newProxyInstance creates a new proxy 
that implements the array of interfaces passed as its second 
parameter. In this example, the proxy implements the Explorer 
interface. All invocations of Explorer methods are then handed off 
to the InvocationHandler that is passed as the third parameter. 

Try running the updated code. You should see that each step of the 
Explorer is logged to System.out.  

The dynamic proxy class solves both of the problems of the 
"by-hand" approach. There is no tedious copying and pasting of 
methods because invoke can handle all methods. Also, the logger 
presented here can be used to log calls to any interface in the 
Java(tm) language. Try inserting some loggers in your own code to 
trace program flow.  

Notice that the logging operation is method generic, that is, 
logging does not require any decision making based on the 
specifics of the method being called. Dynamic proxies are at their 
best when adding method-generic services. Logging is one area 
where dynamic proxies can be used to advantage; others include 
generic stubs for RMI, automatic parameter validation, transaction
enlistment, authentication and access control, and rule-based 
parameter, modification, and error handling.  

Dynamic proxies, like all reflective code, are somewhat slower than 
"normal" code. In many situations this performance difference is 
not crucial. If you want to evaluate the performance of dynamic 
proxies for delegation, download the benchmarking code from 
http://staff.develop.com/halloway/JavaTools.html and execute the 
TimeMethodInvoke.cmd script. This script measures times for various 
styles of method invocation in the Java language.  
 
For more info on dynamic proxies, see  
http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html.  

Any comments? email to:
richard@dreamscity.net