什么是代理(proxy)?使用代理服务器翻过墙的都知道那大概是怎么一回事。比如,我想访问google,结果GFW不允许。假如存在于某地的一台主机可以访问google,并且可以提供访问google的服务,这时我们向这台主机发出访问google的请求,这台主机然后将我们的请求转发给google,并且将google的响应内容返回给我们,那么这个主机就是一个代理了。
Java中的代理是这样定义的,利用代理可以在运行时创建一个实现了一组给定接口的新类。那么具体用在哪儿呢?例如:
- Routing method calls to remote servers
- Associating user interface events with actions in a running program
- Tracing method calls for debugging purposes
第一种用法没接触过,不作讨论。
第二种用法如下,假设有一个标签为Load的按钮,它的事件处理只包含下面一个方法调用frame.loadData()
,使用匿名内部类的写法如下:
loadButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
frame.loadData();
}
});
使用EventHandler类可以自动地创建这样一个监听器:
EventHandler.create(ActionListener.class, frame, "loadData");
第三种用法,用于调试时跟踪方法调用。示例代码及代码解释如下:
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Random;
public class ProxyTest
{
public static void main(String[] args)
{
Object[] elements = new Object[1000];
for (int i = 0; i < elements.length; i++)
{
Integer value = i + 1;
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
elements[i] = proxy;
}
Integer key = new Random().nextInt(elements.length) + 1;
int result = Arrays.binarySearch(elements, key);
if (result >= 0) System.out.println(elements[result]);
}
}
class TraceHandler implements InvocationHandler
{
private Object target;
public TraceHandler(Object c)
{
target = c;
}
@Override
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
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(")");
return m.invoke(target, args);
}
}
以上代码跟踪了Arrays.binarySearch方法的调用过程,由于这个方法不是我们编写的,无法在该方法中添加打印语句之类的实现跟踪。那么该如何做呢?由于binarySearch方法能够排序任何实现了Comparable接口的对象数组。于是我们可以创建一个对象数组,里面的每个元素都是一个代理对象(由Proxy.newProxyInstance方法创建),该对象实现了Comparable接口并且代理了一个Integer原对象,每个原对象被一个InvocationHandler对象持有,每当在代理对象上调用了一个方法m,InvocationHandler对象的invoke方法就被回调,在此处就可以添加一些打印语句等,最后再将方法m施加在原对象上。