代理是一種經常使用的設計模式,其目的就是爲其餘對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。html
代理模式UML圖:java
簡單結構示意圖:設計模式
爲了保持行爲的一致性,代理類和委託類一般會實現相同的接口,因此在訪問者看來二者沒有絲毫的區別。經過代理類這中間一層,能有效控制對委託類對象的直接訪問,也能夠很好地隱藏和保護委託類對象,同時也爲實施不一樣控制策略預留了空間,從而在設計上得到了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。數組
Java動態代理類位於java.lang.reflect包下,通常主要涉及到如下兩個類:函數
(1)Interface InvocationHandler:該接口中僅定義了一個方法this
在實際使用時,第一個參數obj通常是指代理類,method是被代理的方法,如上例中的request(),args爲該方法的參數數組。這個抽象方法在代理類中動態實現。spa
(2)Proxy:該類即爲動態代理類,其中主要包含如下內容:設計
protected Proxy(InvocationHandler h):構造函數,用於給內部的h賦值。代理
static Class getProxyClass (ClassLoaderloader, Class[] interfaces):得到一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的所有接口的數組。code
static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理類的一個實例,返回後的代理類能夠看成被代理類使用(可以使用被代理類的在Subject接口中聲明過的方法)
所謂DynamicProxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,而後該class就宣稱它實現了這些 interface。你固然能夠把該class的實例看成這些interface中的任何一個來用。固然,這個DynamicProxy其實就是一個Proxy,它不會替你做實質性的工做,在生成它的實例時你必須提供一個handler,由它接管實際的工做。
在使用動態代理類時,咱們必須實現InvocationHandler接口
經過這種方式,被代理的對象(RealSubject)能夠在運行時動態改變,須要控制的接口(Subject接口)能夠在運行時改變,控制的方式(DynamicSubject類)也能夠動態改變,從而實現了很是靈活的動態代理關係。
動態代理步驟:
1.建立一個實現接口InvocationHandler的類,它必須實現invoke方法
2.建立被代理的類以及接口
3.經過Proxy的靜態方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)建立一個代理
4.經過代理調用方法
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 實際對象 */ class RealSubject implements Subject { /** * 你好 * * @param name * @return */ public String SayHello(String name) { return "hello " + name; } /** * 再見 * * @return */ public String SayGoodBye() { return " good bye "; } } /** * 調用處理器實現類 * 每次生成動態代理類對象時都須要指定一個實現了該接口的調用處理器對象 */ class InvocationHandlerImpl implements InvocationHandler { /** * 這個就是咱們要代理的真實對象 */ private Object subject; /** * 構造方法,給咱們要代理的真實對象賦初值 * * @param subject */ public InvocationHandlerImpl(Object subject) { this.subject = subject; } /** * 該方法負責集中處理動態代理類上的全部方法調用。 * 調用處理器根據這三個參數進行預處理或分派到委託類實例上反射執行 * * @param proxy 代理類實例 * @param method 被調用的方法對象 * @param args 調用參數 * @return * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在代理真實對象前咱們能夠添加一些本身的操做 System.out.println("在調用以前,我要乾點啥呢?"); System.out.println("Method:" + method); //當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用 Object returnValue = method.invoke(subject, args); //在代理真實對象後咱們也能夠添加一些本身的操做 System.out.println("在調用以後,我要乾點啥呢?"); return returnValue; } } /** * 動態代理演示 */ public class ProxyTest { public static void main(String[] args) { //代理的真實對象 Subject realSubject = new RealSubject(); /** * InvocationHandlerImpl 實現了 InvocationHandler 接口,並能實現方法調用從代理類到委託類的分派轉發 * 其內部一般包含指向委託類實例的引用,用於真正執行分派轉發過來的方法調用. * 即:要代理哪一個真實對象,就將該對象傳進去,最後是經過該真實對象來調用其方法 */ InvocationHandler handler = new InvocationHandlerImpl(realSubject); ClassLoader loader = realSubject.getClass().getClassLoader(); Class[] interfaces = realSubject.getClass().getInterfaces(); /** * 該方法用於爲指定類裝載器、一組接口及調用處理器生成動態代理類實例 */ Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler); System.out.println("動態代理對象的類型:"+subject.getClass().getName()); String hello = subject.SayGoodBye(); System.out.println(hello); // String goodbye = subject.SayGoodBye(); // System.out.println(goodbye); } }