【Java基础】代理 - Proxy

利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。

代理类是在程序运行过程中创建的。然而,一旦被创建,就变成了常规类,与虚拟机中的任何其他类没有什么区别。

对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次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());
	}
}

输出:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值