Java/Reflection/Proxy
Содержание
- 1 A demonstration of a proxy factory
- 2 A dynamic proxy adapter which allows overriding several methods of a target proxy
- 3 A high-performance factory for dynamic proxy objects
- 4 Creating a Proxy Object
- 5 Demonstrates a dangerous use of proxy names
- 6 Demonstrates the basic concept of proxies generated by clients to the proxies
A demonstration of a proxy factory
<source lang="java">
/*
* 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 ########## */
</source>
A dynamic proxy adapter which allows overriding several methods of a target proxy
<source lang="java">
/*
* 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.*
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"); } } </source>
A high-performance factory for dynamic proxy objects
<source lang="java">
/*
* 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 * java.lang.reflect.Proxy.newProxyInstance(), 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 * ProxyFactory 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. * ProxyFactory.newInstance throws IllegalArgumentException * for the same reasons that Proxy.getProxyClass 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 * getProxyClass 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; }
}
</source>
Creating a Proxy Object
<source lang="java">
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(); }
}
</source>
Demonstrates a dangerous use of proxy names
<source lang="java">
/*
* 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 ########## */
</source>
Demonstrates the basic concept of proxies generated by clients to the proxies
<source lang="java">
/*
* 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 ########## */
</source>