代理Proxy:Core Java 6.5

利用代理可以在运行时创建一个实现了一组接口的新类。

这种功能只有在编译时无法确定需要实现哪个接口时才使用。对于应用程序设计人员来说,遇到这种情况的机会很少。这是一种高级技术,对于系统程序设计人员来说,代理带来的灵活性十分重要。

代理如何工作的

代理类可以在运行时创建全新的类。在运行时直接生成类,即Class类的一个实例。而非生成一个类的源码,然后经过编译后再生成类的字节码文件,再经过JVM加载、生成类。因此运行时生成类性能很快。

代理类能够实现指定的接口的所有需要的方法,并且也实现了Object类的toString、equals方法。

代理类并非是通过自己全新的定义来实现这些接口方法的,而是通过一个调用处理器即InvocationHandler接口的一个实例对象来实现的。

InvocationHandler接口中只有一个方法:

/*
@param  poxy 代理类
@param  method  当代理类工作时,调用被代理对象的那个方法;即代理类实现的接口方法。
@param  args   被代理的方法的参数
*/
Object  invoke(Object  proxy, Method method, Object[]  args)

代理类的代理作用即代理要做的工作就要写在这个invoke方法中,再method.invoke(args);方法前后做一些必要的工作。

无论何时调用代理对象的方法,invoke方法都会被调用,invoke方法中必须给出处理调用的代码。

创建代理对象

需要用JDK的Proxy类的newProxyInstance方法:

static Object newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandler h);

在运行时动态生成类,首先要指定类加载器 loader,然后指明对哪些接口——interfaces生成代理类,最后确定生成的代理类最终是调用哪个被代理类的哪些方法——invocationHandler实例——一个调用处理器。

使用代理类的可能场景

  1. 路由对远程服务的方法调用
  2. 在程序运行期间,将用户接口事件与动作关联起来
  3. 为了调试,跟踪方法调用

举个例子

追踪Arrays.binarySearch方法的查找过程:输入查找一个给定的key时,经过了几次比较,每次是同哪个数比较的。
分析:binarySearch方法是JDK的方法,它调用comparable接口的compareTo方法来做比较和查找,我们无法在这个方法里插入代码,来做输出,但是代理可以做到。
代理就是在执行本要做的事情的前后,再做一些其它的事情,来实现代理的功能。

import java.lang.reflect.*;
import java.util.*;

class ComparableProxy implements InvocationHandler
{
	private Object target;

	public IntegerProxy(Object target){
	
		this.target = target;
	}

	public Object invoke(Object p,Method m,Object [] args) throws  Throwable{

		//  在做比较工作前,输入比较对象信息
		StringBuilder sb = new StringBuilder(this.toString()).append("],[target:").append(target.toString()).append("],[args:").append(Arrays.toString(args));

		System.out.println(sb.toString());
		
		// 调用实际工作的比较方法
		return	m.invoke(target,args);

	}
}

import static java.lang.System.out;
import java.util.*;
import java.lang.reflect.*;

public class Test{

    public static void main(String[] args){
		
		Object [] proxys = new Object[1000];

		for(int i=0;i<1000;i++){
			proxys[i] = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, new ComparableProxy(i+1));
		}

		int key = new Random().nextInt(1000) + 1;

		out.println("key:"+key);

		int result = Arrays.binarySearch(proxys, key);

		out.println("result:"+result);
    }
}
/*
key:780
[target:500],[args:[780]
[target:750],[args:[780]
[target:875],[args:[780]
[target:812],[args:[780]
[target:781],[args:[780]
[target:765],[args:[780]
[target:773],[args:[780]
[target:777],[args:[780]
[target:779],[args:[780]
[target:780],[args:[780]
result:779
*/

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

所有的代理类都扩展于 Proxy 类。一个代理类只有一个实例域—调用处理器,它定义超类 Proxy 中。 为了履行代理对象的职责, 所需要的任何附加数据都必须存储在调用处理器中。 例如, 在上例中, 代理 Comparable 对象时, ComparableProxy 包装了实际的对象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章