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
/*
* 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 ########## */