在學習《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()將請求轉發給 被代理對象,並傳入必需的參數。這初看起來可能有些受限,就像你只能執行泛化操作一樣。但是,你可以通過傳遞其他的參數,來過濾某些方法的調用。
