一、代理模式 java
所謂代理,就是一我的或者一個機構表明另外一我的或者另外一個機構採起行動。在一些狀況下,一個客戶不想或者不可以直接引用一個對象,而代理對象能夠在客戶端和目標對象以前起到中介的做用。
代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象的引用。 程序員
生活中的例子:過年加班比較忙,沒空去買火車票,這時能夠打個電話到附近的票務中心,叫他們幫你買張回家的火車票,固然這會附加額外的勞務費。但要清楚票務中心本身並不賣票,只有火車站才真正賣票,票務中心賣給你的票實際上是經過火車站實現的。這點很重要! 數組
上面這個例子,你就是「客戶」,票務中心就是「代理角色」,火車站是「真實角色」,賣票稱爲「抽象角色」! 測試
代理模式JAVA代碼示例:
//抽象角色:抽象類或接口
this
interface Business { void doAction(); }
//代理角色:本身並未實現業務邏輯接口,而是調用真實角色來實現 spa
class BusinessImplProxy implements Business { private BusinessImpl bi; public void doAction() { if (bi==null) { bi = new BusinessImpl(); } doBefore(); bi.doAction(); doAfter(); } public void doBefore() { System.out.println("前置處理!"); } public void doAfter() { System.out.println("後置處理!"); } } //測試類 class Test { public static void main(String[] args) { //引用變量定義爲抽象角色類型 Business bi = new BusinessImplProxy(); bi.doAction(); } }
因此,藉助於JVM的支持,能夠在運行時動態生成代理類(「代理角色」),咱們就能夠解決上述代理模式中代碼膨脹的問題,使用了動態代理後,「代理角色」將不用手動生成,而由JVM在運行時,經過指定類加載器、接口數組、調用處理程序這3個參數來動態生成。 代理
動態代理模式JAVA代碼示例:
code
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Method; //抽象角色:java動態代理的實現目前只支持接口,不支持抽象類 interface BusinessFoo { void foo(); } interface BusinessBar { String bar(String message); } //真實角色:真正實現業務邏輯方法 class BusinessFooImpl implements BusinessFoo { public void foo() { System.out.println("BusinessFooImpl.foo()"); } } class BusinessBarImpl implements BusinessBar { public String bar(String message) { System.out.println("BusinessBarImpl.bar()"); return message; } } //動態角色:動態生成代理類 class BusinessImplProxy implements InvocationHandler { private Object obj; BusinessImplProxy() { } BusinessImplProxy(Object obj) { this.obj = obj; } public Object invoke(Object proxy,Method method,Object[] args) throws Throwable { Object result = null; doBefore(); result = method.invoke(obj,args); doAfter(); return result; } public void doBefore(){ System.out.println("do something before Business Logic"); } public void doAfter(){ System.out.println("do something after Business Logic"); } public static Object factory(Object obj) { Class cls = obj.getClass(); return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new BusinessImplProxy(obj)); } } //測試類 public class DynamicProxy { public static void main(String[] args) throws Throwable { BusinessFooImpl bfoo = new BusinessFooImpl(); BusinessFoo bf = (BusinessFoo)BusinessImplProxy.factory(bfoo); bf.foo(); System.out.println(); BusinessBarImpl bbar = new BusinessBarImpl(); BusinessBar bb = (BusinessBar)BusinessImplProxy.factory(bbar); String message = bb.bar("Hello,World"); System.out.println(message); } }
程序流程說明:
new BusinessFooImpl();建立一個「真實角色」,傳遞給工廠方法BusinessImplProxy.factory(),進而初始化「調用處理器」——即實現InvocationHandler的類。並返回一個動態建立的代理類實例,因爲「代理角色」也必然實現了「抽象角色」提供的業務邏輯方法,故可向下轉型爲BusinessBar,並賦值給指向BusinessBar類型的引用bb。
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法由程序員來指定參數動態返回須要的代理類,而invoke(Object proxy, Method method, Object[] args) 方法則是由JVM在運行時動態調用的。當執行「bb.bar("Hello,World");」方法時,JVM動態指派「調用處理器」,向外層invoke傳遞參數,並調用method.invoke(obj,args)真正執行! 對象
BusinessImplProxy.Factory靜態方法用來動態生成代理類(「代理角色」),在運行時根據不一樣的業務邏輯接口BusinessFoo和BusinessBar,在運行時分別動態生成了代理角色。「抽象角色」、「代理角色」以及調用處理器(實現InvocationHandler接口的類)這三者均可以改變,因此說JAVA的動態代理十分強大。 接口