代理模式屬於結構型模式java
定義:代理模式爲其餘對象提供一種代理以控制對這個對象的訪問。編程
代理模式是java框架層面應用最普遍的少數幾種設計模式之一,很是重要。設計模式
適用場景:安全
遠程代理,爲一個對象在不一樣的地址空間提供局部表明,這樣能夠隱藏一個對象存在於不一樣地址空間的事實。性能優化
虛擬代理,根據須要建立開銷很大的對象,經過它來存放實例化須要很長時間的對象,這樣能夠達到性能優化;框架
安全代理,用來控制真實對象訪問時的權限。通常用於對象應該有不一樣的訪問權限的時候;ide
智能指引,是指當調用真實的對象的時候,代理處理另外的一些事情(用的比較多)性能
代理模式要求代理實現與被代理對象相同的接口(cglib與被代理對象是子類與父類的關係),以保證任什麼時候候都能代替真實對象。這也是它與適配器模式的區別!!測試
代理模式普遍應用於aop編程。可以在不改變源代碼的前提下提供統一的日誌管理,先後置攔截器,符合開放封閉原則、依賴倒置原則,優化
下面代碼屬於靜態代理,大體場景是追求者會追妹子,但他不認識某girl,而經過代理類認識,因此追求者經過代理類對妹子展開了追求。
public class ProxyTest { public static void main(String[] args) { PursuitWay pursuitWay=new Proxy(new Pursuiter(new Girl("小白"))); pursuitWay.giveFlower(); pursuitWay.giveGift(); } } interface PursuitWay{ void giveFlower(); void giveGift(); } class Girl{ private String name; public Girl(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Pursuiter implements PursuitWay{ Girl girl; public Pursuiter(Girl girl){ this.girl=girl; } @Override public void giveFlower() { System.out.println("追求者送"+girl.getName()+"花"); } @Override public void giveGift() { System.out.println("追求者送"+girl.getName()+"禮物"); } } class Proxy implements PursuitWay{ PursuitWay pursuter; public Proxy(PursuitWay pursuiter){ this.pursuter=pursuiter; } @Override public void giveFlower() { pursuter.giveFlower(); } @Override public void giveGift() { pursuter.giveGift(); } }
既然是經過代理去追妹子,那每次苦力活代理作作日誌,設置個障礙就不難理解了吧。
上述功能若是要經過適配器模式實現,則proxy沒必要非要實現PursuitWay,它會有本身的方法而沒必要非要是giveXXX,只須要在它本身的方法中實現pursuter的giveXXX方法就能夠了,具體代碼略。
上述代理模式屬於靜態代理,由於代理類是咱們本身編寫出來的,而動態代理則是經過java虛擬機,在運行期間生成的字節碼。
下述代碼是經過動態代理實現的相同功能
1. 獲取追求者上的全部接口列表;
2. 肯定要生成的代理類的類名,默認爲:com.sun.proxy.$ProxyXXXX ;
3. 根據須要實現的接口信息,在代碼中動態建立 該Proxy類的字節碼;
4 . 將對應的字節碼轉換爲對應的class 對象;
5. 建立InvocationHandler 實例handler,用來處理Proxy全部方法調用;
6. Proxy 的class對象 以建立的handler對象爲參數,實例化一個proxy對象
public class ProxyTest { public static void main(String[] args) { Class clazz=Proxy.getProxyClass(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces()); System.out.println("proxy類爲"+clazz.getName()); System.out.println("proxy實現的接口有"+clazz.getInterfaces()[0].getName()); System.out.println("-----開始生成代理對象(實際上該代理對象就是一個該接口的實現類)"); PursuitWay pursuter=(PursuitWay) Proxy.newProxyInstance(Pursuiter.class.getClassLoader(), Pursuiter.class.getInterfaces(), new MyInvocationHandler(new Pursuiter(new Girl("小白")))); pursuter.giveFlower(); pursuter.giveGift(); } } interface PursuitWay{ void giveFlower(); void giveGift(); } class Girl{ private String name; public Girl(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Pursuiter implements PursuitWay{ Girl girl; public Pursuiter(Girl girl){ this.girl=girl; } @Override public void giveFlower() { System.out.println("追求者送"+girl.getName()+"花"); } @Override public void giveGift() { System.out.println("追求者送"+girl.getName()+"禮物"); } } class MyInvocationHandler implements InvocationHandler{ Object object; public MyInvocationHandler(Object object){ this.object=object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(object, args); } }
上述代碼經過jdk自帶的代理類實現,它和靜態代理類有一樣的侷限性,就是要求被代理類必須有一個或者多個對應具體業務邏輯的接口。myInvocationHandler裏邊的invoke方法中能夠提供攔截、寫日誌等功能。
cglib包的代理類CglibProxy是針對某個類生成一個子類,該子類天然會包括其父類的全部業務邏輯方法。並且不在侷限於必須有上層接口。可是cglib包也要求被代理類不能爲final類,不然繼承不了,測試代碼和動態代理很像,略。
cglib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,理論上比使用Java反射效率要高,不過有大神曾經測試過,貌似性能差很少,並且jdk的動態代理還要比cglib效率高一點點。有興趣的朋友能夠去試試。
歡迎大神交流意見。
下一節將會講解工廠方法模式,該模式在service層應用很廣泛。敬請期待。