java設計模式中有一個設計模式很重要,就是代理模式(PRoxy),代理模式一般涉及到的角色有
抽象角色:聲明真實對象和代理對象的共同接口。
真實角色:用戶要訪問的最終對象,是代理角色所代表的真實對象。
代理角色:用戶可通過代理角色訪問真實角色,代理角色中含有真實角色的引用,可通過該引用操作真實對象,同時代理對象提供與真實對象相同的接口以便在任何時候都能代替真實對象,代理對象可以在執行真實對象操作時,附加其他操作,相當于在實現真實對象的功能額外附加功能。
代理角色在生活中隨處可見,通過代理角色可實現客戶與真實角色的分離,就好像學生在生活中要找兼職,要通過中介來找,真正提供工作的不是中介,而是那些你做兼職的公司,中介相當于代理角色,而找兼職的你是客戶,你兼職的公司是真實角色。
下面是一個簡單的靜態代理的例子

1 package proxy;2 //定義的抽象類,代理角色跟真實角色都要繼承它3 public abstract class Subject4 {5 public abstract void output();6 }Subject
1 package proxy;2 //真實角色,實現Subject抽象類的功能3 public class RealSubject extends Subject4 {5 public void output()6 {7 System.out.println("from real subject");8 }9 } RealSubject
1 package proxy; 2 //代理角色 3 public class ProxySubject extends Subject 4 { 5 private RealSubject realSubject;//含有真實角色的引用 6 7 @Override 8 public void output() 9 {10 this.preOutput();//調用真實角色的方法前執行的方法11 if(null == realSubject)12 {13 realSubject = new RealSubject();14 }15 realSubject.output();//調用真實角色的方法16 this.postOutput();//調用真實角色后執行的方法17 } 18 19 public void preOutput()20 {21 System.out.println("pre output");22 }23 public void postOutput()24 {25 System.out.println("post output");26 }27 }ProxySubject
1 package proxy; 2 //訪問的客戶 3 public class Client 4 { 5 public static void main(String[] args) 6 { 7 Subject subject = new ProxySubject();//生成代理實例 8 subject.output();//調用真實角色的方法 9 }10 }Client
通過代理角色實現了各個角色的各自完成自身的功能,真實角色通過代理角色與客戶聯系在一起,但該代理模式有其缺點,就是真實角色必須是事先已經存在的,并將其作為代理對象的內部屬性,但實際應用時,一個真實角色必須對應一個代理角色,就是說每次定義一個真實角色就要定義一個代理角色,如果大量使用會導致類的急劇增長,此外,如果事先不知道真實角色,就不能使用代理了。不過這個問題可以通過java的動態代理(DynamicProxy)來解決。
動態代理類也是位于java.lang.reflect包下,主要涉及到以下兩個類
1、Interface InvocationHandler:該接口中只定義了一個方法public object invoke(Object obj,Method method,Object[] args) 在實際使用中第一個參數一般是指代理類,method是被代理的方法,args是該方法的參數數組,這個抽象方法會在代理類中動態實現。每一個代理類實例會跟一個InvocationHandler相關,這是jdk里面寫的

2、Proxy:該類是動態代理類,作用的話跟ProxySubject類似,主要內容有
1)protected Proxy(InvocationHandler h):構造函數,用于給內部的h賦值。2)static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部接口的數組。3)staticObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)返回代理類的一個實例,返回后的代理類可以當作被代理類使用(可使用被代理類的在Subject接口法)
動態代理就是在運行時生成class,在生成它時要給它提供一組interface,你可以實現任何一個接口,生成動態代理實例時要提供一個handler(實現了InvocationHandler接口),由它接管實際的工作,所以在使用動態代理類時,我們必須要實現InvocationHandler接口。創建動態代理的步驟如下
1、創建被代理類以及接口
2、創建一個實現接口InvocationHandler的類,并實現invoke方法
3、通過Proxy的靜態方法newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler handler)創建一個代理
4、通過創建的代理來調用方法
下面通過一個實例來說明如何創建動態代理

1 package dynamicProxy;2 //定義被代理類要實現的接口3 public interface Subject {4 public void output(String str);5 6 }Subject
1 package dynamicProxy;2 //實現接口的真實對象3 public class RealSubject implements Subject {4 public void output(String str)5 {6 System.out.println(str+" from real");7 }8 }RealSubject 
1 package dynamicProxy; 2 //該類實現了InvocationHandler接口,并重寫了了invoke方法 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class DynamicSubject implements InvocationHandler{ 7 private Object object = new Object();//用Object可以傳遞任何要代理的類 8 public DynamicSubject(Object obj) 9 {10 this.object = obj;11 }12 13 @Override14 public Object invoke(Object proxy, Method method, Object[] args)15 throws Throwable { 16 System.out.println(method); 17 method.invoke(object, args);//等價于realsubject的output方法 object為要代理的真實對象,args為要傳遞的參數 18 return null;19 }20 21 }DynamicSubject
1 package dynamicProxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Client { 7 public static void main(String[] args) { 8 9 Subject sub = new RealSubject();10 InvocationHandler handler = new DynamicSubject(sub);11 12 Class<?> classType = handler.getClass();13 //生成代理,并把方法調用轉向InvocationHandler,這里生成的subject類宣稱實現了sub.getClass().getInterfaces的所有接口14 Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(), sub.getClass().getInterfaces(),handler);15 subject.output("CIACs");//從這里傳遞參數,和方法到DynamicSubject的invoke16 17 System.out.println(subject.getClass().getName());//打印輸出動態生成代理類的名字18 }19 }Client輸出結果:

動態代理是可用在調試和遠程方法調用中,客戶是通過代理類來調用真實對象的方法。一個代理類可生成很多代理實例,實現了一對多的效果。
新聞熱點
疑難解答