利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。
代理类是在程序运行过程中创建的。然而,一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。
对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,只能够得到同一个类的两个对象。
代理实际上就是java.lang.reflect.Proxy动态地根据所指定的接口生成的class byte。该类会继承Proxy类,并实现所有指定的接口(interfaces参数),最后使用参入的class loader将class byte加载如系统,生成这样的一个类的对象。
在最后的一个示例中,可以看到生成的代理类的继承体系及实现的接口。
代理类 - Proxy
public class Proxy extends Object implements Serializable (java.lang.reflect)
要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法,这个方法有三个参数:
static Object | newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
|
- 一个类加载器:作为Java安全模型的一部分,对于系统类和从因特网上下载来的类,可以使用不同的类加载器。使用null表示使用默认的类加载器(系统类的加载器)。
- 一个Class对象数组,每个元素都是需要实现的接口。
- 一个调用处理器。
调用处理器 - InvocationHandler
public interface InvocationHandler (java.lang.reflect)
Modifier and Type | Method and Description |
---|---|
Object | invoke(Object proxy, Method method, Object[] args)
Processes a method invocation on a proxy instance and returns the result.
|
当调用代理类时,代理类只会调用InvocationHandler的invoke方法,所以真正实现的方法必须在invoke方法中去调用。
示例
系统接口代理
Integer类实现了Comparable接口。
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest {
public static void main(String[] args){
Object[] elements = new Object[100];
// fill elements with proxies for the integer
for (int i = 0; i < elements.length; i++){
Integer value = i + 1;
Class[] interfaces = value.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
elements[i] = proxy;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
if (result >= 0){
System.out.println(elements[result]);
}
}
}
class TraceHandler implements InvocationHandler{
private Object target;
public TraceHandler(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
自定义接口代理
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest2 {
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
((TestInterface)proxy).test();
//((TestClass)proxy).test(); error; Proxy cannot be cast to TestClass
//((TestClass)proxy).test2(); error; Proxy cannot be cast to TestClass
}
}
interface TestInterface{
void test();
}
class TestClass implements TestInterface{
public void test(){
System.out.println("TestClass.test");
}
public void test2(){
System.out.println("TestClass.test2");
}
public String toString(){
return "TestClass Instance";
}
}
class TraceHandler2 implements InvocationHandler{
private Object target;
public TraceHandler2(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
打印代理类
我们使用反射中的打印类信息的方法,查看上面示例中生成的代理类的定义:
public class ReflectionTest{
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
ClassAnalyzer.printClass(proxy.getClass());
}
}
输出: