Sunday, June 19, 2016

Dynamic Proxy

A dynamic proxy class (simply referred to as a proxy class below) is a class that implements a list of interfaces specified at runtime when the class is created, with behavior as described below. A proxy interface is such an interface that is implemented by a proxy class. A proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler. A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments. The invocation handler processes the encoded method invocation as appropriate and the result that it returns will be returned as the result of the method invocation on the proxy instance.

A proxy class has the following properties:
  • Proxy classes are public, final, and not abstract.
  • The unqualified name of a proxy class is unspecified. The space of class names that begin with the string "$Proxy" should be, however, reserved for proxy classes.
  • A proxy class extends java.lang.reflect.Proxy.
  • A proxy class implements exactly the interfaces specified at its creation, in the same order.
  • If a proxy class implements a non-public interface, then it will be defined in the same package as that interface. Otherwise, the package of a proxy class is also unspecified. Note that package sealing will not prevent a proxy class from being successfully defined in a particular package at runtime, and neither will classes already defined by the same class loader and the same package with particular signers.
  • Since a proxy class implements all of the interfaces specified at its creation, invoking getInterfaces on its Class object will return an array containing the same list of interfaces (in the order specified at its creation), invoking getMethods on its Class object will return an array of Method objects that include all of the methods in those interfaces, and invoking getMethod will find methods in the proxy interfaces as would be expected.
  • The Proxy.isProxyClass method will return true if it is passed a proxy class-- a class returned by Proxy.getProxyClass or the class of an object returned by Proxy.newProxyInstance-- and false otherwise.
  • The java.security.ProtectionDomain of a proxy class is the same as that of system classes loaded by the bootstrap class loader, such as java.lang.Object, because the code for a proxy class is generated by trusted system code. This protection domain will typically be granted java.security.AllPermission.
  • Each proxy class has one public constructor that takes one argument, an implementation of the interface InvocationHandler, to set the invocation handler for a proxy instance. Rather than having to use the reflection API to access the public constructor, a proxy instance can be also be created by calling the Proxy.newInstance method, which combines the actions of calling Proxy.getProxyClass with invoking the constructor with an invocation handler.
Lets see an Example:

If you want to call a method then you will use the instance to invoke the method.

Caller à instance.method

If you want to add cross cutting concerns (Logging, Transaction Management,  Audit and Security) to your method then we use the proxy to invoke the method and proxy will do the cross cutting concerns.

 Caller à Proxy à instance.method

Implementation:

IStringService.java:
public interface IStringService {
      public String converToUpperCase(String text);
}

StringService.java:
public class StringService implements IStringService {

      @Override
      public String converToUpperCase(String text) {
            return text != null ? text.toUpperCase() : text;
      }

}

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

public class DynamicServiceProxy implements InvocationHandler {
      private Object target;

      public DynamicServiceProxy(Object target) {
            this.target = target;
      }

      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {      
            // TODO Auto-generated method stub       
            System.out.println("Before: proxy invoke");
            Object result = method.invoke(target, args);
            System.out.println("After: proxy invoke");
            return result;
      }
}

DynamicServiceProxyTest.java:
package com.lnn.proxy.string;

import java.lang.reflect.Proxy;

public class DynamicServiceProxyTest {
      public static void main(String[] args) {
            IStringService stringService = new StringService();
            DynamicServiceProxy proxy = new DynamicServiceProxy(stringService);
            ClassLoader classLoader = DynamicServiceProxyTest.class.getClassLoader();
            IStringService proxyService = (IStringService) Proxy.newProxyInstance(classLoader, new Class[]{IStringService.class}, proxy);
            String name = "Lenin Kumar Koppoju";
            String upper = proxyService.converToUpperCase(name);
            System.out.println(upper);
      }
}

Creating Static Proxy (or) Understanding Proxy

If you want to call a method then you will use the instance to invoke the method.

Caller à instance.method

If you want to add cross cutting concerns (Logging, Transaction Management,  Audit and Security) to your method then we use the proxy to invoke the method and proxy will do the cross cutting concerns.

 Caller à Proxy à instance.method

Implemenation:

IStringService.java:
public interface IStringService {
      public String converToUpperCase(String text);
}

StringService.java:
public class StringService implements IStringService {

      @Override
      public String converToUpperCase(String text) {
            return text != null ? text.toUpperCase() : text;
      }

}

StringServiceProxy.java:
public class StringServiceProxy implements IStringService {

      private IStringService stringService;

      public StringServiceProxy(IStringService stringService) {
            this.stringService = stringService;
      }

      @Override
      public String converToUpperCase(String text) {
            System.out.println("Before : calling the service");
            String result = stringService.converToUpperCase(text);
            System.out.println("After : calling the service");
            return result;
      }

}

StringServiceProxyTest.java:
public class StringServiceProxyTest {
      public static void main(String[] args) {
            IStringService stringService = new StringService();
            StringServiceProxy stringServiceProxy = new StringServiceProxy(stringService);
            String name = "Lenin Kumar Koppoju";
            String upper = stringServiceProxy.converToUpperCase(name);
            System.out.println(upper);
      }
}