java設計模式自我總結---代理模式
代理模式是給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用,通俗的來講代理模式就是我們生活中常見的中介。
Spring 的AOP面向切面就是使用動態代理模式來實現的;
打個比方說:我要買房,但是我對該地區房屋的資訊掌握的不夠全面,希望找一個更熟悉的人(中介)去幫我找,此處的代理就是這個意思。
代理類分為靜態代理類和動態代理類:
首先看下靜態代理類,程式碼如下:
介面:
public interface Source { void method(); }
委託類:
/** * 委託類 */ public classRealSubject implements Source { @Override public void method() { System.out.println("我要去買房了"); } }
1、靜態代理類:
/** * 靜態代理類 */ public class ProxySubject implements Source{ private RealSubject realSubject; public ProxySubject() { this.realSubject = newRealSubject(); } @Override public void method() { before(); realSubject.method(); after(); } void before(){ System.out.println("找房"); } void after(){ System.out.println("買房後裝修"); } }
測試類:
public classText { public static void main(String[] args) { Source source = new ProxySubject(); source.method(); } }
輸出結果:
找房
我要去買房了
買房後裝修
靜態代理總結:
優點:可以做到在符合開閉原則的情況下對目標物件進行功能擴充套件。
缺點:我們得為每一個服務都建立代理類,工作量太大,不易管理。同時介面一旦發生改變,代理類也得相應修改。
2、動態代理類
動態代理類中我們不需要手動的建立代理類,我們只需要手動的編寫一個動態處理器就可以了,真正的代理物件由JDK在執行時為我們動態的進行建立;
Dynamic代理模式相對於靜態代理,大大減少了我們的開發任務,同時減少了對業務介面的依賴,降低了耦合度;
動態代理的實現依靠於InvocationHandler介面和Proxy類來實現的,每一個動態代理類中都必須要實現InvocationHandler介面,該介面中有唯一的invoke()方法;
該方法的作用就是得到一個動態的代理物件,其接收三個引數:
loader: 第一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入
interfaces: 第二個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了
h: 第三個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上
我們來看一下程式碼:
首先定義一個介面,有兩個方法
public interface Source { void describe(); void buyHourse(); }
給該介面定義一個實現類,其實就是我們的委託物件
public class SourceImpl implements Source { @Override public void describe() { System.out.println("中國風"); } @Override public void buyHourse() { System.out.println("購房"); } }
定義動態代理類,注意一定要實現介面 InvocationHandler
public class DynamicProxy implements InvocationHandler{ /**這個就是要代理的委託物件,使用Object型別,可以代理不同型別的物件,便於複用*/ private Object source; /**構造器,給要代理的物件賦值*/ public DynamicProxy(Object source) { this.source = source; } /* 我的理解:當我們通過動態代理物件呼叫委託物件的方法時會執行該方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); /*當代理物件呼叫真實物件的方法時,其會自動的跳轉到代理物件關聯的handler物件的invoke方法來進行呼叫*/ method.invoke(source,args); after(); return null; } void before(){ System.out.println("呼叫物件方法前執行的業務邏輯"); } void after(){ System.out.println("呼叫物件方法後執行的業務邏輯"); } }
測試類
public class Test { public static void main(String[] args) { //要代理的真實物件 Source realSource = new SourceImpl(); //建立handler例項,我們要代理哪個物件就把該物件傳進去,最後通過該真是物件來呼叫其方法 InvocationHandler handler = new DynamicProxy(realSource); /** * 通過Proxy.newProxyInstance方法來建立代理物件, * 第一個引數是目標物件的類載入器,獲取方法為geiClassLoader() * 第二個引數是一個Interface物件的陣列,表示的是將要給需要代理的物件提供一組什麼藉口, * 如果我提供了一組介面給它,那麼這個代理物件就可以實現該介面(多型), * 這樣就能呼叫這組介面中的方法了 * 這裡我們為代理物件提供的介面是真實物件所實行的介面,表示要代理的是該真是物件, * 這樣就可以呼叫這組介面中的方法了 * 第三個引數handler,指定的動態代理處理器,將該動態處理器傳入真實的代理物件,即委託類物件 */ Source source = (Source) Proxy.newProxyInstance(Source.class.getClassLoader(), realSource.getClass().getInterfaces(),handler); source.describe(); System.out.println(""); source.buyHourse(); } }
輸出結果
呼叫物件方法前執行的業務邏輯
中國風
呼叫物件方法後執行的業務邏輯
呼叫物件方法前執行的業務邏輯
購房
呼叫物件方法後執行的業務邏輯
OK,至此兩個常見的代理模式就到這裡了,明天說一下使用第三方外掛實現的CGLIB代理模式;下班了回家!!祝大家中秋節快樂!!!
持續更新中...
參考連結: https://www.cnblogs.com/daniels/p/8242592.html
https://www.cnblogs.com/xiaoluo501395377/p/3383130.html