Java中的動態代理
動態代理類
Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:
1.Interface InvocationHandler(調用處理器)
接口說明:InvocationHandler 是由 一個代理實例的調用處理器 實現的接口。
每一個代理實例都會有一個與之關聯的 調用處理器。當我們調用某一個代理實例上的某一個方法的時候,這個方法調用就會被編碼並派發到與之關聯的調用處理器的 invoke() 方法上。
該接口中僅定義了一個方法:
Object invoke(Object proxy, Method method, Object[] args)
方法說明:處理一個代理實例上的方法調用,並返回結果。 當我們調用一個代理實例上的某一個方法的時候,與之關聯的調用處理器上的invoke()方法就會被執行。
在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,如上例中的request(),args爲該方法的參數數組(無參時設置爲null)。
這個抽象方法在代理類中動態實現。
2.Proxy
類說明:Proxy 爲創建動態代理類和實例 提供靜態方法,它還是被那些靜態方法創建的動態代理類的父類。
該類即爲動態代理類,作用類似於上文例子中的ProxySubject,其中主要包含如下內容:
protected Proxy(InvocationHandler h): 構造函數,用於給內部的invocation handler賦值。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) : loader是類裝載器,interfaces是真實類所擁有的全部接口的數組。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) :返回代理類的一個實例,返回後的代理類可以當作被代理類使用(可使用被代理類在Subject接口中聲明過的方法)。
動態代理類說明
所謂Dynamic Proxy是這樣一種class:
它是在運行時生成的class,在生成它時你必須提供一組interface給它,然後該class就宣稱它實現了這些interface。
你當然可以把該class的實例當作這些interface中的任何一個來用。
當然,這個Dynamic Proxy其實就是一個Proxy,它不會替你做實質性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作。
在使用動態代理類時,我們必須實現InvocationHandler接口。每一個動態代理類都會有一個與之關聯的invocation handler。
真正的調用是在invocation handler的invoke()方法裏完成的。
實例說明:
首先定義抽象角色和真實角色類:
public interface Subject { public void request(); }
public class RealSubject implements Subject { @Override public void request() { System.out.println("From real subject!"); } }
之後定義一個DynamicSubject類:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 該代理類的內部屬性是Object類型,實際使用的時候通過該類的構造方法傳遞進來一個對象。 * 該類實現了invoke()方法,該方法中的method.invoke()其實就是調用被代理對象的將要執行的方法, * 方法參數sub表示該方法從屬於sub。 * 通過動態代理類,我們可以在執行真實對象的方法前後加入自己的一些額外方法 * */ public class DynamicSubject implements InvocationHandler { //對真實對象的引用 private Object sub; public DynamicSubject(Object obj) { this.sub = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before calling: " + method); //通過反射來調用方法 method.invoke(sub, args); System.out.println("After calling: " + method); return null; } }
使用的時候:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); // 下面的代碼一次性生成代理 // $Proxy0是在運行期間動態生成的一個類 // 動態生成一個類(實現了指定的接口),生成類的對象,實現真實對象所實現的接口,強制轉換成接口類型(Subject) // subject是 $Proxy0 類型的一個實例 Subject subject = (Subject) Proxy.newProxyInstance(classType .getClassLoader(), realSubject.getClass().getInterfaces(), handler);
// 調用方法時,轉移給handler接管,由其中的invoke()方法實際完成方法執行subject.request();
// 打印出:class $Proxy0System.out.println(subject.getClass()); }}
通過這種方式,被代理的對象(RealSubject)可以在運行時動態改變,需要控制的接口(Subject接口)可以在運行時改變,控制的方式(DynamicSubject類)也可以動態改變,從而實現了非常靈活的動態代理關係。
動態代理
動態代理是指客戶通過代理類來調用其他對象的方法。
動態代理使用場合:
調試。
遠程方法調用(RMI)。
動態代理步驟
1.創建一個實現接口InvocationHandler的類,它必須實現invoke()方法。
2.創建被代理的類以及接口。
3.通過Proxy的靜態方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)創建一個代理。
4.通過代理調用方法。
動態代理實現例子2:
import java.util.List; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Vector; public class VectorProxy implements InvocationHandler { private Object proxyObj; public VectorProxy(Object obj) { this.proxyObj = obj; } public static Object factory(Object obj) { Class<?> classType = obj.getClass(); return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), new VectorProxy(obj)); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before calling: " + method); // 打印出方法參數 if (args != null) { for (Object obj : args) { System.out.println(obj); } } // 調用方法 Object object = method.invoke(proxyObj, args); System.out.println("After calling: " + method); return object; } public static void main(String[] args) { List v = (List) factory(new Vector()); System.out.println(v.getClass().getName()); v.add("New"); v.add("York"); System.out.println(v); v.remove(0); System.out.println(v); } }
動態代理實現例子3:
這個例子中定義了一個接口:
public interface Foo { public void doAction(); }
這個接口有兩個實現類:
public class FooImpl1 implements Foo { @Override public void doAction() { System.out.println("From Implement 1 !"); } } public class FooImpl2 implements Foo { @Override public void doAction() { System.out.println("From Implement 2 !"); } }
定義invocation handler,其中的set方法使得實際對象是可更換的:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class CommonInvocationHandler implements InvocationHandler { private Object target; public CommonInvocationHandler() { } public CommonInvocationHandler(Object obj) { this.target = obj; } public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } }
使用:
import java.lang.reflect.Proxy; public class Demo { public static void main(String[] args) { CommonInvocationHandler handler = new CommonInvocationHandler(); Foo f = null; handler.setTarget(new FooImpl1()); f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler); f.doAction(); System.out.println("----------------------------"); handler.setTarget(new FooImpl2()); f.doAction(); } }
程序運行後輸出:
From Implement 1 !
----------------------------
From Implement 2 !
參考資料
聖思園張龍老師Java SE系列視頻。