About Martin Mois

Martin is a Java EE enthusiast and works for an international operating company. He is interested in clean code and the software craftsmanship approach. He also strongly believes in automated testing and continuous integration.

Implementing dynamic proxies – a comparison

Sometimes there is the need to intercept certain method calls in order to execute your own logic everytime the intercepted method is called. If you are not within in Java EE’s CDI world and don’t want to use AOP frameworks like aspectj, you have a simple and similar effective alternative.

Since version 1.5 the JDK comes with the class java.lang.reflect.Proxy that allows you to create a dynamic proxy for a given interface. The InvocationHandler that sits behind the dynamically created class is called everytime the application invokes a method on the proxy. Hence you can control dynamically what code is executed before the code of some framework or library is called.

Next to JDK’s Proxy implementation bytecode frameworks like javassist or cglib offert similar functionality. Here you can even subclass an exiting class and decide which methods you want to forward to the superclass’s implementation and which methods you want to intercept. This comes of course with the burden of another library your project depends on and that may have to be updated from time to time whereas JDK’s Proxy implementation is already included in the runtime environment.

So let’s take a closer look and try these three alternatives out. In order to compare javassist’s and cglib’s proxy with the JDK implementation we need an interface that is implemented by a simple class, because the JDK mechanism only supports interfaces and no subclassing:

public interface IExample {
    void setName(String name);
}

public class Example implements IExample {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

In order to delegate the method calls on the proxy to some real object, we create an instance of the Example class above and call it within the InvocationHandler via a final declared variable:

final Example example = new Example();
InvocationHandler invocationHandler = new InvocationHandler() {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		return method.invoke(example, args);
	}
};
return (IExample) Proxy.newProxyInstance(JavaProxy.class.getClassLoader(), new Class[]{IExample.class}, invocationHandler);

As you can see from the code sample the creation of a proxy a rather simple: Call the static method newProxyInstance() and provide a ClassLoader, an array of interfaces that should be implemented by the proxy as well as an instance of the InvocationHandler interface. Our implementation forwards for the sake of demonstration only the instance of Example we have created before. But in real life you can of course perform more advanced operations that evaluate for example the methods name or its arguments.

Now we take a look at the way the same is done using javassist:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Example.class);
Class aClass = factory.createClass();
final IExample newInstance = (IExample) aClass.newInstance();
MethodHandler methodHandler = new MethodHandler() {
	@Override
	public Object invoke(Object self, Method overridden, Method proceed, Object[] args) throws Throwable {
		return proceed.invoke(newInstance, args);
	}
};
((ProxyObject)newInstance).setHandler(methodHandler);
return newInstance;

Here we have a ProxyFactory that wants to know for which class it should create a subclass. Then we let the ProxyFactory create a whole class that can be reused as many times as necessary. The MethodHandler is here analog to the InvocationHandler the one that gets called for each method invocation of the instance. Here again we just forward the call to an instance of Example we have created before.

Last but not least let’s take a look at cglib’s proxy:

final Example example = new Example();
IExample exampleProxy = (IExample) Enhancer.create(IExample.class, new MethodInterceptor() {
	@Override
	public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		return method.invoke(example, args);
	}
});
return exampleProxy;

In the cglib world we have an Enhancer class that we can use to implement a given interface with a MethodInterceptor instance. The implementation of the callback method looks very similar to the one in the javassist example. We just forward the method call via reflection API to the already existing instance of Example.

Now that we have seen three different implementations we also want to evaluate their runtime behavior. Therefore we write s simple unit test, that measures the execution time of each of these implementations:

@Test
public void testPerformance() {
	final IExample example = JavaProxy.createExample();
	long measure = TimeMeasurement.measure(new TimeMeasurement.Execution() {
		@Override
		public void execute() {
			for (long i = 0; i < JavassistProxyTest.NUMBER_OF_ITERATIONS; i++) {
				example.setName("name");
			}
		}
	});
	System.out.println("Proxy: "+measure+" ms");
}

We choose a huge number of iterations in order to stress the JVM and to let the HotSpot compiler create native code for the often executed passages. The following chart shows the average runtime of the three implementations:

2014-01-14_proxies_chart

To show the impact of a Proxy implementation at all, the chart also shows the execution times for the standard invocation of the method on the Example object (“No proxy”). First of all we can put to record that the proxy implementations are about 10 times slower than the plain invocation of the method itself. But we also notice a difference between the three proxy solutions. JDK’s Proxy class is surprisingly nearly as fast as the cglib implementation. Only javassist pulls out with about twice the exeuction time of cglib.

Conclusion: Runtime proxies are easy to use and you have different way of doing it. JDK’s Proxy only supports proxies for interfaces whereas javassist and cglib allow you to subclass existing classes. The runtime behavior of a proxy is about 10 times slower than a standard method invocation. The three solutions also differ in terms of runtime.
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

6 Responses to "Implementing dynamic proxies – a comparison"

  1. Curios Coder says:

    What were the measurements in for the test?

  2. Robert says:

    For completeness, I think you are missing a crucial comparison… what if you had a “manual proxy” that simply delegated the call… e.g.

    class ManualProxy implements IExample
    {
    private final IExample upstream;

    ManualProxy(IExample upstream)
    {
    this.upstream=upstream;
    }

    public void setName(String name)
    {
    upstream.setName(name);
    }

    }

  3. Martin says:

    Hello Robert,

    a simple Delegate implementation is exactly what is shown in the figure with the label “No proxy”.

    • Robert says:

      According to the write up, “no proxy” was using the example object directly, so I suspect that a “manual proxy” would be roughly twice that.

      BTW, is there a link to download this source, or must I stitch it together from the segments to replicate the test?

Leave a Reply


− two = 1



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close