Dynamic proxy in Java

Advanced

Dynamic proxy allows us to implement interfaces dynamically by handling method calls in an InvocationHandler. It allows us to intercept method calls and reroute them or add functionality dynamically or do things like security checks,logging etc.

Dynamic Proxy Usage

  • AOP frameworks like Spring AOP uses dynamic proxy to address the issue of crosscutting concerns.
  • Database Connection and Transaction Management
  • Security
  • Logging
  • Performing extra checks on arguments
  • Implement lazy access to costly resources
  • Creating dynamic implementations of interfaces at runtime

How to Create Dynamic Proxy

We can create dynamic proxy using the Proxy.newProxyInstance() method. The newProxyInstance()methods takes 3 parameters:

  1. The ClassLoader that is to “load” the dynamic proxy class.
  2. An array of interfaces to implement.
  3. An InvocationHandler to forward all methods calls on the proxy to.
SimpleClass simpleClass = new SimpleClass();
InvocationHandler simpleClassHandler = new ProxyInvocationHandler(simpleClass);
SimpleInterface simpleInterfaceProxy = (SimpleInterface) Proxy.newProxyInstance(simpleClass.getClass().getClassLoader(),
simpleClass.getClass().getInterfaces(),simpleClassHandler);

Let us look into InvocationHandler, the real implementer.

InvocationHandler

All method calls to the dynamic proxy are forwarded to InvocationHandler implementation. we have to implement invoke method of InvocationHandler.

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

It processes a method invocation on a proxy instance and returns the result. It will be invoked on an invocation handler when a method is invoked on a proxy instance associated with it.

proxy:  dynamic proxy object implementing the interface.
method: represents the method called on the interface the dynamic proxy implements.
args: contains the parameter values passed to the proxy when the method in the interface implemented was called.

public class ProxyInvocationHandler implements InvocationHandler {

private Object obj;

public ProxyInvocationHandler(Object obj) {
this.obj = obj;
}

public ProxyInvocationHandler() {
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if (obj != null) {
System.out.println(“Before ” + methodName + ” invocation”);
Object result = method.invoke(obj, args);
System.out.println(“After ” + methodName + ” invocation”);
return result;
}
return null;
}

}

Let us look into few examples wherein we can make use of Dynamic Proxies.

Example 1 : Creating dynamic implementations of interfaces at runtime

Animal Interface

package com.dynamic.proxy;

public interface Animal {

public void description(String type);

}

ProxyInvocationHandler Class

package com.dynamic.proxy;

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

public class ProxyInvocationHandler implements InvocationHandler {

private Object obj;

public Object getObj() {
return obj;
}

public void setObj(Object obj) {
this.obj = obj;
}

public ProxyInvocationHandler(Object obj) {
this.obj = obj;
}

public ProxyInvocationHandler() {
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (proxy instanceof Animal) {
if (methodName.equals(“description”) && args != null
&& args.length == 1) {
System.out.println(“This is a ” + args[0]);
}
}
return null;
}

public static void main(String[] args) {
InvocationHandler animalHandler = new ProxyInvocationHandler();
Animal animalProxy = (Animal) Proxy.newProxyInstance(
Animal.class.getClassLoader(), new Class[] { Animal.class },
animalHandler);
animalProxy.description(“Dog”);
animalProxy.description(“Cat”);
animalProxy.description(“Tiger”);
}

}

Output:
This is a Dog
This is a Cat
This is a Tiger

Example 2 : Intercepting method calls

SimpleInterface

package com.dynamic.proxy;

public interface SimpleInterface {

public void test();

public String test1();

}

SimpleClass

package com.dynamic.proxy;

public class SimpleClass implements SimpleInterface{

public void test(){
System.out.println(“Inside test”);
}

public String test1(){
System.out.println(“Inside test1”);
return “testString”;
}

}

ProxyInvocationHandler

package com.dynamic.proxy;

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

public class ProxyInvocationHandler implements InvocationHandler {

private Object obj;

public ProxyInvocationHandler(Object obj) {
this.obj = obj;
}

public ProxyInvocationHandler() {
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (obj != null) {
System.out.println(“Before ” + methodName + ” invocation”);
Object result = method.invoke(obj, args);
System.out.println(“After ” + methodName + ” invocation”);
return result;
}
return null;
}

public static void main(String[] args) {
SimpleClass simpleClass = new SimpleClass();
InvocationHandler simpleClassHandler = new ProxyInvocationHandler(
simpleClass);
SimpleInterface simpleInterfaceProxy = (SimpleInterface) Proxy
.newProxyInstance(simpleClass.getClass().getClassLoader(),
simpleClass.getClass().getInterfaces(),
simpleClassHandler);
simpleInterfaceProxy.test();
System.out.println(“Return value:” + simpleInterfaceProxy.test1());
}

}

Output:
Before test invocation
Inside test
After test invocation
Before test1 invocation
Inside test1
After test1 invocation
Return value:testString

Leave a Reply

Your email address will not be published. Required fields are marked *