Java/Reflection/Proxy

Материал из Java эксперт
Перейти к: навигация, поиск

A demonstration of a proxy factory

  
/*
 *     file: SomeClassFactory.java
 *  package: oreilly.hcj.proxies
 *
 * This software is granted under the terms of the Common Public License,
 * CPL, which may be found at the following URL:
 * http://www-124.ibm.ru/developerworks/oss/CPLv1.0.htm
 *
 * Copyright(c) 2003-2005 by the authors indicated in the @author tags.
 * All Rights are Reserved by the various authors.
 *
 ########## DO NOT EDIT ABOVE THIS LINE ########## */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * An invocation handler that counts the number of calls for all methods in the
 * target class.
 * 
 * @author 
 * @version $Revision: 1.2 $
 */
public class DemoCountingProxy {
  /**
   * Run the demonstration.
   * 
   * @param args
   *          Command Line Arguments (ignored).
   */
  public static final void main(final String[] args) {
    SomeClassCountingProxy proxy = SomeClassFactory.getCountingProxy();
    proxy.someMethod();
    proxy.someOtherMethod("Our Proxy works!");
    System.out.println("Method Invocation Count = " + proxy.getInvocationCount());
  }
}
/* ########## End of File ########## */





A dynamic proxy adapter which allows overriding several methods of a target proxy

 
/*
 * Copyright 2006-2007 The Scriptella Project Team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * A dynamic proxy adapter which allows overriding several
 * methods of a target proxy.
 * <p>To create a proxy adapter for Interface, create subclass of
 * ProxyAdapter and define methods from Interface you want to handle,
 * other methods invocations will be failed.
 *
 * @author Fyodor Kupolov
 * @version 1.0
 */
public class ProxyAdapter<T> {
    private final T proxy;
    @SuppressWarnings("unchecked")
    public ProxyAdapter(Class... interfaces) {
        proxy = (T) Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Method m;
                try {
                    //Determine if the method has been defined in a subclass
                    m = ProxyAdapter.this.getClass().getMethod(method.getName(), method.getParameterTypes());
                    m.setAccessible(true);
                } catch (Exception e) { //if not found
                    throw new UnsupportedOperationException(method.toString(), e);
                }
                //Invoke the method found and return the result
                try {
                    return m.invoke(ProxyAdapter.this, args);
                } catch (InvocationTargetException e) {
                    throw e.getCause();
                }
            }
        });
    }
    /**
     * @return proxy instance implementing T.
     */
    public T getProxy() {
        return proxy;
    }

    /**
     * Usage example
     */
    public static void main(String[] args) throws Exception {
        //Create adapter for Appendable
        ProxyAdapter<Appendable> pa = new ProxyAdapter(Appendable.class) {
            private StringBuilder sb = new StringBuilder();
            //Override only 2 methods: append and toString
            public Appendable append(char c) {
                System.out.println("Proxy append(char c) method. Append "+c);
                sb.append(c);
                return (Appendable) getProxy();
            }
            public String toString() {
                return "Proxy toString method: "+sb;
            }
        };
        final Appendable a = pa.getProxy();
        a.append("1").append("2");
        System.out.println("a.toString() = " + a.toString());
        //this invocation fails because no method has been created
        a.append("Not implemented");
    }
}





A high-performance factory for dynamic proxy objects

 
/*
 * Copyright 2006 (C) TJDO.
 * All rights reserved.
 *
 * This software is distributed under the terms of the TJDO License version 1.0.
 * See the terms of the TJDO License in the documentation provided with this software.
 *
 * $Id: ProxyFactory.java,v 1.1 2006/08/11 20:41:59 jackknifebarber Exp $
 */

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;

/**
 * A high-performance factory for dynamic proxy objects.
 * <p>
 * A ProxyFactory performs the same function as
 * <tt>java.lang.reflect.Proxy.newProxyInstance()</tt>, but does so for a single
 * set of interfaces.
 * It holds a (soft) reference to the proxy class constructor and so can create
 * many proxies of the same type with very little overhead.
 * <p>
 * The generated proxy class is assigned the same class loader as the
 * <tt>ProxyFactory</tt> class itself.
 *
 * @author 
 * @version $Revision: 1.1 $
 */
public class ProxyFactory
{
    private final Class[] interfaces;
    private Reference ctorRef;

    /**
     * Creates a factory for proxy objects that implement the specified
     * interface.
     *
     * @param intfc
     *      the interface for the proxy class to implement
     */
    public ProxyFactory(Class intfc)
    {
        this(new Class[] { intfc });
    }
    /**
     * Creates a factory for proxy objects that implement the specified
     * interface(s).
     *
     * @param interfaces
     *      the list of interfaces for the proxy class to implement
     */
    public ProxyFactory(Class[] interfaces)
    {
        this.interfaces = interfaces;
    }
    /**
     * Returns an instance of a proxy class for this factory"s interfaces that
     * dispatches method invocations to the specified invocation handler. 
     * <tt>ProxyFactory.newInstance</tt> throws <tt>IllegalArgumentException</tt>
     * for the same reasons that <tt>Proxy.getProxyClass</tt> does.
     *
     * @param handler
     *      the invocation handler to dispatch method invocations to 
     * @return
     *      a proxy instance with the specified invocation handler of a proxy
     *      class that implements this factory"s specified interfaces 
     *
     * @throws IllegalArgumentException
     *      if any of the restrictions on the parameters that may be passed to
     *      <tt>getProxyClass</tt> are violated 
     * @throws NullPointerException
     *      if the invocation handler is null
     */
    public Object newInstance(InvocationHandler handler)
    {
        if (handler == null)
            throw new NullPointerException();
        try
        {
            return getConstructor().newInstance(new Object[] { handler });
        }
        catch (InstantiationException e)    { throw new InternalError(e.toString()); }
        catch (IllegalAccessException e)    { throw new InternalError(e.toString()); }
        catch (InvocationTargetException e) { throw new InternalError(e.toString()); }
    }
    private synchronized Constructor getConstructor()
    {
        Constructor ctor = ctorRef == null ? null : (Constructor)ctorRef.get();
        if (ctor == null)
        {
            try
            {
                ctor = Proxy.getProxyClass(getClass().getClassLoader(), interfaces)
                            .getConstructor(new Class[] { InvocationHandler.class });
            }
            catch (NoSuchMethodException e)
            {
                throw new InternalError(e.toString());
            }
            ctorRef = new SoftReference(ctor);
        }
        return ctor;
    }
}





Creating a Proxy Object

  
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface MyInterface {
  void method();
}
class MyInterfaceImpl implements MyInterface {
  public void method() {
    System.out.println("method");
  }
}
class ProxyClass implements InvocationHandler {
  Object obj;
  public ProxyClass(Object o) {
    obj = o;
  }
  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
    Object result = null;
    try {
      System.out.println("before the method is called ");
      result = m.invoke(obj, args);
    } catch (Exception eBj) {
    } finally {
      System.out.println("after the method is called"); 
    }
    return result;
  }
}
public class Main {
  public static void main(String[] argv) throws Exception {
    MyInterface myintf = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(),
        new Class[] { MyInterface.class }, new ProxyClass(new MyInterfaceImpl()));
    myintf.method();
  }
}





Demonstrates a dangerous use of proxy names

  
/*
 *     file: SomeClassFactory.java
 *  package: oreilly.hcj.proxies
 *
 * This software is granted under the terms of the Common Public License,
 * CPL, which may be found at the following URL:
 * http://www-124.ibm.ru/developerworks/oss/CPLv1.0.htm
 *
 * Copyright(c) 2003-2005 by the authors indicated in the @author tags.
 * All Rights are Reserved by the various authors.
 *
 ########## DO NOT EDIT ABOVE THIS LINE ########## */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * An invocation handler that counts the number of calls for all methods in the
 * target class.
 * 
 * @author 
 * @version $Revision: 1.2 $
 */
public class DangerousNames {
  /** 
   * Run the demonstration.
   *
   * @param args Command line arguments (ignored).
   */
  public static final void main(final String[] args) {
    SomeClass proxy = SomeClassFactory.getDynamicSomeClassProxy();
    System.out.println(proxy.getClass().getName());
    try {
      Class cl = Class.forName("$Proxy0");  // <== Dangerous!
      System.out.println(cl.getName());
    } catch (final ClassNotFoundException ex) {
      ex.printStackTrace();
    }
  }
}
/* ########## End of File ########## */





Demonstrates the basic concept of proxies generated by clients to the proxies

  
/*
 *     file: SomeClassFactory.java
 *  package: oreilly.hcj.proxies
 *
 * This software is granted under the terms of the Common Public License,
 * CPL, which may be found at the following URL:
 * http://www-124.ibm.ru/developerworks/oss/CPLv1.0.htm
 *
 * Copyright(c) 2003-2005 by the authors indicated in the @author tags.
 * All Rights are Reserved by the various authors.
 *
 ########## DO NOT EDIT ABOVE THIS LINE ########## */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * An invocation handler that counts the number of calls for all methods in the
 * target class.
 * 
 * @author 
 * @version $Revision: 1.2 $
 */
public class DemoClientGeneratedProxy {
  /** 
   * Run the demonstration.
   *
   * @param args Command Line Arguments (ignored).
   */
  public static final void main(final String[] args) {
    SomeClassProxy proxy = new SomeClassProxy(new SomeClassImpl("Fred"));
    proxy.someMethod();
    proxy.someOtherMethod("Our Proxy works!");
  }
}
/* ########## End of File ########## */