原文鏈接:http://www.orlion.ga/207/ 一、代理模式 代理模式是經常用到的設計模式,代理模式是給指定對象提供代理對象。由代理對象來控制具體對象的引用。 代理模式涉及到的角色: 抽象主題角色:聲明瞭代理主題和真實主題的公共介面,使任何需要真實主題的地方都能用代理主題代替。 代理主 ...
原文鏈接:http://www.orlion.ga/207/
一、代理模式
代理模式是經常用到的設計模式,代理模式是給指定對象提供代理對象。由代理對象來控制具體對象的引用。
代理模式涉及到的角色:
抽象主題角色:聲明瞭代理主題和真實主題的公共介面,使任何需要真實主題的地方都能用代理主題代替。
-
代理主題角色:含有真實主題的引用,從而可以在任何時候操作真實主題,代理主題功過提供和真實主題相同的介面,使它可以隨時代替真實主題。代理主題通過持有真實主題的引用,不但可以控制真實主題的創建或刪除,可以在真實主題被調用前進行攔截,或在調用後進行某些操作。
真實代理對象:定義了代理角色所代表的具體對象。
(設計模式是通用的)
按照代理創建的時期代理類可以分成兩種:
靜態代理:由程式員創建或特定工具自動生成源代碼,再對其編譯。在程式運行前,代理類的.class文件就已經存在 了。
動態代理:在程式運行時,運用反射機制動態創建而成。
二、靜態代理
Talk is cheap,show me the code
首先定義個酒廠的介面:
WineFactory.java
package ml.orlion.proxy; public interface WineFactory { public void sell(); }
然後再定義一個酒廠類實現這個介面:
WineFactoryImpl.java
package ml.orlion.proxy; public class WineFactoryImpl implements WineFactory{ @Override public void sell() { System.out.println("賣酒"); } }
然後定義一個代理類,對酒廠進行代理:
WineFactoryProxy.java
package ml.orlion.proxy; /** * 代理類 * 對WineFactoryImpl進行代理 */ public class WineFactoryProxy implements WineFactory{ private WineFactory winef; public WineFactoryProxy(WineFactory winef){ this.winef = winef; } @Override public void sell() { System.out.println("賣酒之前..."); winef.sell(); System.out.println("賣酒之後..."); } }
三、動態代理
由靜態代理的代碼可以看到靜態代理只能對一個介面進行服務,如果項目中有很多個介面,那麼肯定會產生過多的代理。這時候就需要用到動態代理,由一個代理類完成所有的代理功能。動態代理類的位元組碼在程式運行時由Java反射機制動態生成,無需程式員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟體系統的可擴展性,因為Java 反射機制可以生成任意類型的動態代理類。
JDK動態代理中包含一個InvocationHandler介面和一個Proxy類
(1)InvocationHandler介面
public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }
其中Object porxy:是被代理的對象
Method method:要調用的方法
Object[] args:要調用的方法的參數
(2)Proxy類
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個介面動態地生成實現類,此類提供瞭如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
其中ClassLoader loader:是類載入器;
(在java中主要有三種類載入器:
Booststrap ClassLoader:此載入器採用C++編寫,一般開發中是看不到的;
Extendsion ClassLoader:用來進行擴展類的載入,一般對應的是jrelibext目錄中的類;
AppClassLoader:(預設)載入classpath指定的類,是最常使用的是一種載入器。
)
Class<?>[] interfaces:得到全部介面;
InvocationHandler h:得到InvocationHandler介面的子類實例;
code:
WineFactory.java和WineFactoryImpl.java和靜態代理的代碼相同。
WineFactoryInvocationHandler.java:
package ml.orlion.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * JDK動態代理類 * 對WineFactoryImpl進行代理 */ public class WineFactoryInvocationHandler implements InvocationHandler{ private Object target; @Override public Object invoke(Object porxy, Method m, Object[] args) throws Throwable { Object result = null; beforeMethod(); // 執行 result = m.invoke(target, args); afterMethod(); return result; } public void beforeMethod(){ System.out.println("賣酒之前..."); } public void afterMethod(){ System.out.println("賣酒之後..."); } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } }
測試:
// 產生一個被代理對象 WineFactory wf = new WineFactoryImpl(); // 將被代理對象交給InvocationHandler WineFactoryInvocationHandler wfih = new WineFactoryInvocationHandler(); wfih.setTarget(wf); // 根據被代理對象產生一個代理 WineFactory wfp = (WineFactory)Proxy.newProxyInstance(wf.getClass().getClassLoader(), wf.getClass().getInterfaces(), wfih); wfp.sell();
除了JDK動態代理外還有一種cglib動態代理,具體可參考文章(本文參考):http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html