在Java中利用代理(Proxy)可以在运行时创建一个实现了一组给定接口的新类。
在系统程序设计中,有时需要面对无法确定接口,却需要构造对象的情况。以前为了解决此问题,有些程序根据动态确定的接口,生成Java类文件,然后调用类
加载器构造该对象,然后使用,这样一来无可避免性能问题。通过代理类,能够在不额外创建Java文件的情况下构造对象及调用该对象方法。
使用代理的理由有很多,其中就有如下的情况:
1.路由对远程服务器的方法调用
2.在程序运行期间,将用户接口事件与行动关联起来
3.调试时跟踪方法调用
以下举出一例,使用代理和调用处理器跟踪方法调用
1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3 import java.lang.reflect.Proxy;
4 import java.util.Arrays;
5 import java.util.Random;
6
7 public class ProxyTest
8 {
9 public static void main(String[] args)
10 {
11 Object[] elements = new Object[1000];
12
13 // fill elements with proxies for the integers 1
1000
14 for (int i = 0; i < elements.length; i++)
15 {
16 Integer value = i + 1;
17 Class[] interfaces = value.getClass().getInterfaces();
18 InvocationHandler handler = new TraceHandler(value);
19 Object proxy = Proxy.newProxyInstance(null,
20 interfaces, handler);
21 elements[i] = proxy;
22 }
23
24 // construct a random integer
25 Integer key = new Random().nextInt(elements.length) + 1;
26
27 // search for the key
28 int result = Arrays.binarySearch(elements, key);
29
30 // print match if found
31 if (result >= 0) System.out.println(elements[result]);
32 }
33 }
34
35 /**
36 An invocation handler that prints out the method name
37 and parameters, then invokes the original method
38 */
39 class TraceHandler implements InvocationHandler
40 {
41 /**
42 Constructs a TraceHandler
43 @param t the implicit parameter of the method call
44 */
45 public TraceHandler(Object t)
46 {
47 target = t;
48 }
49
50 public Object invoke(Object proxy, Method m, Object[] args) throws Throwable//此方法在代理类中
51 { //的方法被调用时均会被调用
52 // print implicit argument
53 System.out.print(target);
54 // print method name
55 System.out.print("." + m.getName() + "(");
56 // print explicit arguments
57 if (args != null)
58 {
59 for (int i = 0; i < args.length; i++)
60 {
61 System.out.print(args[i]);
62 if (i < args.length - 1)
63 System.out.print(", ");
64 }
65 }
66 System.out.println(")");
67
68 // invoke actual method
69 // return new Integer("123");
70 return m.invoke(target, args);
71 }
72
73 private Object target;
74 }
75
在此处,代理类取代了可能需要额外创建的Java文件。
当调用代理类的方法时,调用实现InvocationHandler接口的方法invoke,此时可以针对传入参数Method的不同,定义不同的方法体(操作)
Proxy类的特性:
1.代理(Proxy)类只有一个实例变量,即调用处理器(InvocationHandler)
2.代理类需要的额外数据都必须存储在调用处理器中
3.代理类一定是public和final.
4.如果代理类实现的所有接口都是public,则代理类就不属于某个特定的包;否则所有的非公有接口都必须属于同一个包,代理类也属于这个包(此设定的目的是确定代理类的所属包)