Intercept method calls using dynamic Proxy

[Updated: May 19, 2017, Created: Mar 6, 2016]

In this example, we are going to demonstrate how to use the JDK interface based proxies to intercept method calls.

The method interceptor can provide AOP style 'around advice'.

In this simple example we are just logging calls, before and after the method invocation on underlying object.

This example also demonstrates how to delegate the calls to underlying original object.

It's good to have compatible interfaces between the underlying object and the proxied interface but that's not the absolute requirement.



Implementing InvocationHandler

 public class MyInvocationHandler implements InvocationHandler {

    private String theString;

    public MyInvocationHandler (String theString) {
    this.theString = theString;
    }

    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("before method call : " + method.getName());
    Object result = method.invoke(theString, args);
    System.out.println("after method call : " + method.getName());
    return result;
    }
}



Creating and proxing the String object

To keep things simple and to demonstrate the basic concept well, we chose java.lang.CharSequence interface and the implementing class String.

Here's how we link the original String object to it's proxied CharSequence interface:

public static void main (String[] args) {

        MyInvocationHandler handler = new MyInvocationHandler("the example string");

        CharSequence o = (CharSequence) Proxy.newProxyInstance(
                            MyInvocationHandler.class.getClassLoader(),
                            new Class[]{CharSequence.class}, handler);
        System.out.println(o.length());
        System.out.println(o.subSequence(4, 8));
    }


Output:

before method call : length
after method call : length
18
before method call : subSequence
after method call : subSequence
exam

Generic method Interceptor

Let's rewrite our above interceptor for any object:

public class MyInterceptor<T> implements InvocationHandler {

  private T t;

  public MyInterceptor(T t) {
      this.t = t;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("before method call : " + method.getName());
      Object result = method.invoke(t, args);
      System.out.println("after method call : " + method.getName());
      return result;
  }

  @SuppressWarnings("unchecked")
  public static <T> T getProxy(T t, Class<? super T> interfaceType) {
      MyInterceptor handler = new MyInterceptor(t);
      return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(),
              new Class<?>[]{interfaceType}, handler
      );
  }
}
public class MyInterceptorExample {
  public static void main(String[] args) {
      List<String> list = MyInterceptor.getProxy(new ArrayList<>(), List.class);
      list.add("one");
      list.add("two");
      System.out.println(list);
      list.remove("one");
  }
}

Output

before method call : add
after method call : add
before method call : add
after method call : add
before method call : toString
after method call : toString
[one, two]
before method call : remove
after method call : remove

Example Project

Dependencies and Technologies Used :

  • JDK 1.8
  • Maven 3.0.4

Java Dynamic Proxies Select All Download
  • jdk-dynamic-proxy-interceptor
    • src
      • main
        • java
          • com
            • logicbig
              • example

See Also