JDK Dynamic Proxies

08 November 2014
By Gonçalo Marques
In this article we will cover JDK Dynamic Proxies along with their contribution to the Aspect Oriented Programming paradigm

Introduction

JDK Dynamic Proxies allow one to create implementations of Java interfaces at runtime by the means of Reflection. A proxy may be seen as a subject that will forward method calls to target instances and eventually return any result produced by the target instance to the caller. Since the invocation chain will pass through the proxy, the proxy itself will also be able to do arbitrary processing before and after the target method invocation.

The aforementioned proxy features should make us conclude that proxies may be used to implement several design patterns, for example the Proxy, Facade and Decorator patterns.

One of the main paradigms of Aspect Oriented Programming (AOP) is the separation of cross cutting concerns from business logic. Code that implement concerns like transaction management, logging or validation (among many others) should not reside within classes that implement business logic itself. So it is natural that frameworks that make heavy usage of AOP will absolutely rely on proxying mechanism.

The very popular Spring Framework uses JDK Dynamic Proxies as one of its proxy creation strategies. When we declare a Transactional method inside a Spring service, the container will create a proxy that will intercept calls to the target method and decorate it with the required transaction management instructions.

The JDK Dynamic Proxy

We start by creating a simple business interface and an illustrative implementation:

ServiceOne

public interface ServiceOne {

  String sayHello();

}



ServiceOneBean

public class ServiceOneBean implements ServiceOne {

  @Override
  public String sayHello() {
    System.out.println("Executing method sayHello");
    return "Hello";
  }

}

In this article we will create a proxy that logs method execution times. For this we may define a proxy like the following:

LogExecutionTimeProxy

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class LogExecutionTimeProxy implements InvocationHandler {

  // The target instance
  private Object invocationTarget;

  public LogExecutionTimeProxy(Object invocationTarget) {
    this.invocationTarget = invocationTarget;
  }

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

    // Start time
    long startTime = System.nanoTime();

    // Invoke the method on the target instance
    Object result = method.invoke(invocationTarget, args);

    // Print the execution time
    System.out.println("Executed method " + method.getName() + " in "
        + (System.nanoTime() - startTime) + " nanoseconds");

    // Return the result to the caller
    return result;
  }

}

A dynamic proxy must implement the InvocationHandler interface. This interface has a single method - invoke() - that will be used to forward methods to an arbitrary target instance. One may decorate the method interception with any code required. In the presented case we are logging the target instance method execution time.

We may now use our just defined dynamic proxy:

Dynamic Proxy usage

import java.lang.reflect.Proxy;

public class Main {

  public static void main(String args[]) {

    // Create the target instance
    ServiceOne serviceOne = new ServiceOneBean();

    // Create the proxy
    ServiceOne proxy = (ServiceOne) 
        Proxy.newProxyInstance(ServiceOne.class.getClassLoader(), 
          serviceOne.getClass().getInterfaces(),
          new LogExecutionTimeProxy(serviceOne));

    // Invoke the target instance method through the proxy
    String result = proxy.sayHello();

    System.out.println("Result: " + result);

  }

}

The dynamic proxy instance is created through the Proxy.newProxyInstance() static method call. This method receives three arguments: The class loader that will be responsible for loading our proxy instance, the interfaces that our proxy will implement, and finally the user defined proxy (the one that implements the InvocationHandler interface).

One should now conclude that a JDK Dynamic Proxy must implement at least a single interface.

When we execute the above test method, the following output will be generated:

Executing method sayHello
Executed method sayHello in 1447164 nanoseconds
Result: Hello

Relationship with AOP

The mechanism we have just seen is the basis for many Aspect Oriented Programming frameworks. This is one of the ways that Spring uses to wire cross cutting concerns to our declared Spring beans. Spring will use the annotation based configuration (or XML configuration) in order to understand which concerns must be wired to the existing Spring beans and create the respective proxies. The proxies will then be injected into client instances providing a subtle way of hiding all cross cutting details from the business implementation.

Curiosity about Java 8

Since InvocationHandler interface is a single method interface, it is considered as a functional interface (more information in Java 8 Lambda expressions and Java 8 Method References).

We could have defined our proxy using a lambda expression:

Dynamic Proxy using a lambda expression

// Create the target instance
ServiceOne serviceOne = new ServiceOneBean();

// Create the proxy
ServiceOne serviceOneProxy = (ServiceOne) Proxy.newProxyInstance(
    ServiceOne.class.getClassLoader(), serviceOne.getClass()
        .getInterfaces(), (proxy, method, args) -> {

      // Start time
    long startTime = System.nanoTime();

    // Invoke the method on the target instance
    Object result = method.invoke(serviceOne, args);

    // Print the execution time
    System.out.println("Executed method " + method.getName()
        + " in " + (System.nanoTime() - startTime)
        + " nanoseconds.");

    // Return the result to the caller
    return result;

  });

// Invoke the target instance method through the proxy
serviceOneProxy.sayHello();

Reference

Proxy (Java Platform SE)

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: