在学习《Java编程思想》的时候看到了动态代理,觉得很有意思,现在来做一下总结。
一、代理模式的定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
二、优点
三、模式结构
一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。
四、UML示意图
我们来看一个普通代理实现的例子:
1 //客户端接口
2 interface Interface { 3
4 void doSomething(); 5
6 void somethingElse(String arg); 7 } 8
9 //客户端实现类,就是执行业务逻辑的类
10 class RealObject implements Interface { 11
12 @Override 13 public void doSomething() { 14 // TODO Auto-generated method stub
15 System.out.println("doSomething"); 16 } 17
18 @Override 19 public void somethingElse(String arg) { 20 // TODO Auto-generated method stub
21 System.out.println("somethingElse" + arg); 22 } 23
24 } 25
26 //代理类
27 class SimpleProxy implements Interface { 28
29 private Interface proxied; 30
31 public SimpleProxy(Interface proxied) { 32 // TODO Auto-generated constructor stub
33 this.proxied = proxied; 34 } 35
36 @Override 37 public void doSomething() { 38 // TODO Auto-generated method stub
39 System.out.println("SimpleProxy doSomething"); 40 proxied.doSomething(); 41 } 42
43 @Override 44 public void somethingElse(String arg) { 45 // TODO Auto-generated method stub
46 System.out.println("SimpleProxy somethingElse "+arg); 47 proxied.somethingElse(arg); 48 } 49
50 } 51
52 public class SimpleProxyDemo{ 53
54 public static void consumer(Interface iface){ 55 iface.doSomething(); 56 iface.somethingElse("hello world"); 57 } 58
59 public static void main(String[] args){ 60 consumer(new RealObject()); 61 System.out.println("/*****************************/"); 62 consumer(new SimpleProxy(new RealObject())); 63 } 64 }
运行结果如下:
1 doSomething 2 somethingElsehello world 3 /*****************************/
4 SimpleProxy doSomething 5 doSomething 6 SimpleProxy somethingElse hello world 7 somethingElsehello world
五、Java动态代理
Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作揭示调用的类型并确定相应的对策。
接下来我们来看一下Java动态代理的例子:
1 interface Interface { 2
3 void doSomething(); 4
5 void somethingElse(String arg); 6 } 7
8 class RealObject implements Interface { 9
10 @Override 11 public void doSomething() { 12 // TODO Auto-generated method stub
13 System.out.println("doSomething"); 14 } 15
16 @Override 17 public void somethingElse(String arg) { 18 // TODO Auto-generated method stub
19 System.out.println("somethingElse" + arg); 20 } 21
22 } 23
24 //动态代理类
25 class DynamicProxyHandler implements InvocationHandler{ 26
27 private Object proxied; 28
29 public DynamicProxyHandler(Object proxied) { 30 // TODO Auto-generated constructor stub
31 this.proxied = proxied; 32 } 33
34 @Override 35 public Object invoke(Object proxy, Method method, Object[] args) 36 throws Throwable { 37 // TODO Auto-generated method stub
38 System.out.println("****proxy: " + proxy.getClass()+
39 ", method: "+method+ ", args: "+ args); 40
41 if(args != null){ 42 for (Object arg : args) { 43 System.out.println(" "+ arg); 44 } 45 } 46
47 return method.invoke(proxied, args); 48 } 49 } 50
51 class SimpleDynamicProxy{ 52
53 public static void consumer(Interface iface){ 54 iface.doSomething(); 55 iface.somethingElse("hello world"); 56 } 57
58 public static void main(String[] args){ 59 RealObject real = new RealObject(); 60 consumer(real); 61
62 System.out.println("/*******************************/"); 63
64 Interface proxy = (Interface)Proxy.newProxyInstance( 65 Interface.class.getClassLoader(), 66 new Class[]{Interface.class}, 67 new DynamicProxyHandler(real)); 68
69 consumer(proxy); 70
71 } 72
73 }
运行结果如下:
1 doSomething 2 somethingElsehello world 3 /*******************************/
4 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.doSomething(), args: null
5 doSomething 6 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@756095fc 7 hello world 8 somethingElsehello world
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理。这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器执行其中介任务时,可以将请求转发。
invoke()方法传递进来了代理对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。然而,在invoke()内部,在代理上调用方法时需要格外小心,因为接口的调用将被重定向为对代理对象的调用。
通常,你会执行被代理的操作,然后使用Method.invoke()将请求转发给 被代理对象,并传入必需的参数。这初看起来可能有些受限,就像你只能执行泛化操作一样。但是,你可以通过传递其他的参数,来过滤某些方法的调用。