Java Reflection in Action Study Note 5

Dynamic proxy

The key to Proxy is : implementation and delegation.  The proxy implements the same interface as the target so that it can be used in exactly the same way.  The proxy delegates some or all of the calls that it receives  to its target and thus acts as either an intermediary or substitute.  Such like RMI, proxies are local substitutes for remote object.

Method invocation intercession  

intercession is the goal we want to achieve.  By java’s reflective ability we could modifies the behavior of a program by directly taking control of its behavior.

image

Invocation Handlers

Proxy allows programmers to  accomplish the delegation task by providing the InvocaionHandler interface. Invocation handler take the charge of handle each method call for a proxy instance.

 image

let’s give a complete example how proxy has been achieved by java reflection.

1. TracingIH.java

public class TracingIH implements InvocationHandler
{

    public static Object createProxy( Object obj, PrintWriter out )
    {
        return Proxy.newProxyInstance( obj.getClass( ).getClassLoader( ), obj
                .getClass( ).getInterfaces( ), new TracingIH( obj, out ) );
    }

    private Object target;
    private PrintWriter out;

    private TracingIH( Object obj, PrintWriter out )
    {
        target = obj;
        this.out = out;
    }

    public Object invoke( Object proxy, Method method, Object[] args )
            throws Throwable
    {
        Object result = null;
        try
        {
            out.println( method.getName( ) + "(...) called" ); //$NON-NLS-1$
            result = method.invoke( target, args );
        }
        catch ( InvocationTargetException e )
        {
            out.println( method.getName( ) + " throws " + e.getCause( ) ); //$NON-NLS-1$
            throw e.getCause( );
        }
        out.println( method.getName( ) + " returns" ); //$NON-NLS-1$
        return result;
    }
}

TracingIH is an instance of invocation in the above class, there is a private field named ‘target’, this object store the reference of the invoked target class

The dynamic class creation is accomplished with the static ‘NewProxyInstance’ method, which is embeded in createProxy() method.  for InvocationHandler interface, ‘invoke’ method has been implemented.

in this ‘invoke’ method,  we intercept the code with some diagnostic info, from the info we could get some debug clue during the code execution running time, which would be very useful. you can imagine by using proxy user could inject some behavior to the original target class.

DogFactory.java

ublic class DogFactory
{

    private Class dogClass;
    private boolean traceIsOn = false;

    public DogFactory( String className, boolean trace )
    {
        try
        {
            dogClass = Class.forName( className );
        }
        catch ( ClassNotFoundException e )
        {
            throw new RuntimeException( e ); // or whatever is appropriate
        }
        traceIsOn = trace;
    }

    public Dog newInstance( String name, int size )
    {
        try
        {
            Dog d = ( Dog ) dogClass.newInstance( );
            d.initialize( name, size );
            if ( traceIsOn )
            {
                d = ( Dog ) TracingIH.createProxy( d, new PrintWriter(
                        System.out, true ) );
            }
            else
            {
                d = ( Dog ) SynchronizedIH.createProxy( TracingIH.createProxy(
                        d,
                        new PrintWriter( System.out, true ) ) );
            }
            return d;
        }
        catch ( InstantiationException e )
        {
            throw new RuntimeException( e ); // or whatever is appropriate
        }
        catch ( IllegalAccessException e )
        {
            throw new RuntimeException( e ); // or whatever is appropriate
        }
    }

see this code:

( Dog ) TracingIH.createProxy( d, new PrintWriter( System.out, true ) );

createProxy would create a proxy for the dog instance.  then each time if the user call the method for ‘Dog’ instance, the proxy would intercept the call and inject some logic into the executing method in runtime.

public class ProxyTest
{

    /**
     * @param args
     */
    public static void main( String[] args )
    {
        
        
        DogFactory df = new DogFactory( "javaStudy.reflection.proxy.DogImpl", true ); //$NON-NLS-1$
        
        Dog proxyDog = df.newInstance( "givava", 6 ); //$NON-NLS-1$
        
        proxyDog.method2( );
        
        /*Thread th1 = new ProxyThread( "thread 1", proxyDog ); //$NON-NLS-1$
        Thread th2 = new ProxyThread( "thread 2", proxyDog ); //$NON-NLS-1$
        th1.start( );
        th2.start( );*/
        
    }

}

Here is the test class, the proxy is transparent to the user, when user call method2(), some tracing info would be print out. the output is like this:

dog’s name is : givava
dog’s size is : 6
method2(…) called
Dog(1,1)
method2 returns

About jsdom

leading software engineer
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment