Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 232 posts at DZone. You can read more from them at their website. View Full User Profile

The Power of Proxies in Java

  • submit to reddit

In this article, I’ll show you the path that leads to true Java power, the use of proxies.

They are everywhere but only a handful of people know about them. Hibernate for lazy loading entities, Spring for AOP, LambdaJ for DSL, only to name a few: they all use their hidden magic. What are they? They are… Java’s dynamic proxies.

Everyone knows about the GOF Proxy design pattern:

Allows for object level access control by acting as a pass through entity or a placeholder object.

Likewise, in Java, a dynamic proxy is an instance that acts as a pass through to the real object. This powerful pattern let you change the real behaviour from a caller point of view since method calls can be intercepted by the proxy.

Pure Java proxies

Pure Java proxies have some interesting properties:

  • They are based on runtime implementations of interfaces
  • They are public, final and not abstract
  • They extend java.lang.reflect.Proxy

In Java, the proxy itself is not as important as the proxy’s behaviour. The latter is done in an implementation of java.lang.reflect.InvocationHandler. It has only a single method to implement:

public Object invoke(Object proxy, Method method, Object[] args)
  • proxy: the proxy instance that the method was invoked on
  • method: the Method instance corresponding to the interface method invoked on the proxy instance. The declaring class of the Method object will be the interface that the method was declared in, which may be a superinterface of the proxy interface that the proxy class inherits the method through
  • args: an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or null if interface method takes no arguments. Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper class, such as java.lang.Integer or java.lang.Boolean

Let’s take a simple example: suppose we want a List that can’t be added elements to it. The first step is to create the invocation handler:

public class NoOpAddInvocationHandler implements InvocationHandler {

  private final List proxied;

  public NoOpAddInvocationHandler(List proxied) {

    this.proxied = proxied;

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    if (method.getName().startsWith("add")) {

      return false;

    return method.invoke(proxied, args);

The invoke method will intercept method calls and do nothing if the method starts with “add”. Otherwise, it will the call pass to the real proxied object. This is a very crude example but is enough to let us understand the magic behind.

Notice that in case you want your method call to pass through, you need to call the method on the real object. For this, you’ll need a reference to the latter, something the invoke method does not provide. That’s why in most cases, it’s a good idea to pass it to the constructor and store it as an attribute.

Note: under no circumstances should you call the method on the proxy itself since it will be intercepted again by the invocation handler and you will be faced with a StackOverflowError.

To create the proxy itself:

 List proxy = (List) Proxy.newProxyInstance(
  new Class[] { List.class },
  new NoOpAddInvocationHandler(list));

The newProxyInstance method takes 3 arguments:

  • the class loader
  • an array of interfaces that will be implemented by the proxy
  • the power behind the throne in the form of the invocation handler

Now, if you try to add elements to the proxy by calling any add methods, it won’t have any effect.

CGLib proxies

Java proxies are runtime implementations of interfaces. Objects do not necessarily implement interfaces, and collections of objects do not necessarily share the same interfaces. Confronted with such needs, Java proxies fail to provide an answser.

Here begins the realm of CGLib. CGlib is a third-party framework, based on bytecode manipulation provided by ASM that can help with the previous limitations. A word of advice first, CGLib’s documentation is not on par with its features: there’s no tutorial nor documentation. A handful of JavaDocs is all you can count on. This said CGLib waives many limitations enforced by pure Java proxies:

  • you are not required to implement interfaces
  • you can extend a class

For example, since Hibernate entities are POJO, Java proxies cannot be used in lazy-loading; CGLib proxies can.

There are matches between pure Java proxies and CGLib proxies: where you use Proxy, you use net.sf.cglib.proxy.Enhancer class, where you use InvocationHandler, you use net.sf.cglib.proxy.Callback. The two main differences is that Enhancer has a public constructor and Callback cannot be used as such but only through one of its subinterfaces:

  • Dispatcher: Dispatching Enhancer callback
  • FixedValue: Enhancer callback that simply returns the value to return from the proxied method
  • LazyLoader: Lazy-loading Enhancer callback
  • MethodInterceptor: General-purpose Enhancer callback which provides for “around advice”
  • NoOp: Methods using this Enhancer callback will delegate directly to the default (super) implementation in the base class

As an introductory example, let’s create a proxy that returns the same value for hash code whatever the real object behind. The feature looks like a MethodInterceptor, so let’s implement it as such:

<public class HashCodeAlwaysZeroMethodInterceptor implements MethodInterceptor {

  public Object intercept(Object object, Method method, Object[] args,
    MethodProxy methodProxy) throws Throwable {

    if ("hashCode".equals(method.getName())) {

      return 0;

    return methodProxy.invokeSuper(object, args);

Looks awfully similar to a Java invocation handler, doesn’t it? Now, in order to create the proxy itself:

Object proxy = Enhancer.create(
  new HashCodeAlwaysZeroMethodInterceptor());

Likewise, the proxy creation isn’t suprising. The real differences are:

  • there’s no interface involved in the process
  • the proxy creation process also creates the proxied object. There’s no clear cut between proxy and proxied from the caller point of view
  • thus, the callback method can provide the proxied object and there’s no need to create and store it in your own code


This article only brushed the surface of what can be done with proxies. Anyway, I hope it let you see that Java has some interesting features and points of extension, whether out-of-the-box or coming from some third-party framework

You can find the sources for this article in Eclipse/Maven format here.



Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)



Irek IrekM replied on Tue, 2010/05/11 - 2:02pm

Of course I do agree with you - Enhancers and Proxies are powerful, however have also some limitations:
- Proxies: need to implement an interface
- Enhancers: need o make non-final methods in non-final class (to enable CGLIB to generate a subclass)
- ugly factory method: Proxy.newProxyInstance or Enhancer.create; why not to use just 'new'
- both of them won't work in J2ME applications

 The solution of all these problems is @AspectJ (AspectJ written in Java annotations). Here's the article:

Nicolas Frankel replied on Wed, 2010/05/12 - 2:27am in response to: Irek IrekM

I do agree with you too: AOP (aspect oriented programming) gives a nice abstraction over plain proxy "plumbing". Yet, you can ask yourself why Hibernate, Spring, LambdaJ and all do not use this abstraction layer...

Jakub Holý replied on Wed, 2010/05/12 - 4:23am

Java dynamic proxies are really powerful, though not as easy to create as I'd like (compared e.g. to Mockito's partial mocks). I've used them to good effect for example to improve troubleshooting for failed batch updates with prepared statements, where I need to know what data were in the failed batch to be able to recognize what caused the JDBC error -

Irek IrekM replied on Wed, 2010/05/12 - 12:13pm


why hibernate/spring don't use AOP - IMO there  are 2 reasons:

- the license of AspectJ is Eclipse Public License, which is incompatible with Hibernate's LGPL - it was impossible to add support to AspectJ to Hibernate, for this reason Hibernate still uses CGLIB

- Spring fully supports AspectJ - you can write AspectJ aspects and Spring will understand them at runtime:; no Proxy, no Enhancer


So unless you are writing a project which is to be GPL-compatible (GPL or LGPL license), you can freely use AspectJ as people actually do.

Nicolas Frankel replied on Wed, 2010/05/12 - 5:16pm in response to: Irek IrekM

Well, Spring, although it supports AspectJ, does not use it itself. AOP is a way of seeing the world that the above frameworks do not need (and thus do not use).

I must admit it's only supposition on my part so the debate could go forever but IMHO, I don't think it's a licensing problem.Thanks for your input though.

Manish Kkumar replied on Sun, 2011/07/31 - 10:07am

An informative blog on Dynamic Proxies. For an introduction, see this blog also

Michael Eric replied on Wed, 2012/09/26 - 3:53pm

“limitations enforced by pure Java proxies:
- you are not required to implement interfaces”

I think that pure Java proxies doesn’t have such limitation:

Object proxy = Proxy.newProxyInstance(null, new Class[] { }, handler);

System.out.println(Arrays.toString(proxy.getClass().getInterfaces())); // returns []

In this there way there is no interface involved. Maybe Java API should have clarification for that (interfaces – the list of interfaces for the proxy class to implement).


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.