推薦學習:《》
"代理"這個詞相信大家並不陌生,簡單來說就是代替廠家來售賣商品,代理替代廠家售賣商品,顧客找代理購買商品。也就是說:1)顧客和廠家之間是不可見的,顧客不知道背後的廠家是誰。2)代理可以對顧客進行「定位」,更精確的售賣給需要的客戶群體。
代理模式:為其他物件提供一種代理以控制對這個物件的存取,也就是建立一個代理物件作為使用者端和目標物件之間的中介,主要目的就是保護目標物件或增強目標物件
通過使用代理模式,通常有以下兩個優點:
\1) 可以隱藏被代理類的實現
\2) 可以實現客戶與被代理類間的解耦,在不修改被代理類程式碼的情況下能夠做一些額外的處理
所謂的動態代理,就是通過宣告一個明確的代理類來存取源物件,一個代理只能服務於一種產品,當有n種產品時,就需要n個代理,這樣就不利於業務的發展。
舉例:我們有兩個介面,Mouse和Keyboard,每個介面都有一個實現類
實現類中的程式碼如下:
public class LogitechMouse implements Mouse{ @Override public void sell() { System.out.println("出售羅技滑鼠"); } } public class HHKBKeyboard implements Keyboard{ @Override public void sell() { System.out.println("出售HHKB鍵盤"); } }
現在我們要做的就是讓代理在呼叫sell()
前輸出一句售前瞭解,呼叫後輸出一句售後服務
那我們只需寫兩個代理類MouseProxy
和KeyboardProxy
public class MouseProxy implements Mouse { private Mouse mouse; public MouseProxy(Mouse mouse) { this.mouse = mouse; } @Override public void sell() { System.out.println("售前瞭解"); mouse.sell(); System.out.println("售後服務"); } } public class KeyboardProxy implements Keyboard{ private Keyboard keyboard; public KeyboardProxy(Keyboard keyboard) { this.keyboard = keyboard; } @Override public void sell() { System.out.println("售前瞭解"); keyboard.sell(); System.out.println("售後服務"); } }
最終執行為:
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); MouseProxy mouseProxy = new MouseProxy(logitechMouse); mouseProxy.sell(); Keyboard hhkbKeyboard = new HHKBKeyboard(); KeyboardProxy keyboardProxy = new KeyboardProxy(hhkbKeyboard); keyboardProxy.sell(); } }
輸出:
售前瞭解
出售羅技滑鼠
售後服務
售前瞭解
出售HHKB鍵盤
售後服務
靜態代理的程式碼非常簡單易懂,這種模式雖好,但是也有明顯的缺點:
那麼這個時候就可以使用動態代理來解決了
代理類在程式執行時建立代理的方式叫動態代理,也就是說代理類並不是在java程式碼中定義的,而是在執行的時候動態生成的
JDK從1.3版本就開始支援動態代理類的建立。主要核心類只有2個:java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
還是上面的例子,用JDK動態代理如下:
public class JDKProxy implements InvocationHandler { private Object object; public JDKProxy(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("售前瞭解"); Object invoke = method.invoke(object, args); System.out.println("售後服務"); return invoke; } }
當我們呼叫代理類物件的方法時,這個「呼叫」會轉送到invoke方法中,
代理類物件作為proxy引數傳入,
引數method標識了我們具體呼叫的是代理類的哪個方法,
args為這個方法的引數。
這樣一來,我們對代理類中的所有方法的呼叫都會變為對invoke的呼叫,這樣我們可以在invoke方法中新增統一的處理邏輯(也可以根據method引數對不同的代理類方法做不同的處理)。因此我們可以在中介類的invoke方法中實現輸出售前瞭解,再呼叫被代理類的方法,再輸出售後服務。
執行程式碼
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); JDKProxy jdkProxy = new JDKProxy(logitechMouse); Mouse mouse= (Mouse)Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Mouse.class}, jdkProxy); mouse.sell(); HHKBKeyboard hhkbKeyboard = new HHKBKeyboard(); JDKProxy jdkProxy1 = new JDKProxy(hhkbKeyboard); Keyboard keyboard = (Keyboard)Proxy.newProxyInstance(jdkProxy1.getClass().getClassLoader(), new Class[]{Keyboard.class}, jdkProxy1); keyboard.sell(); } }
可以看到無論多少個介面,只需要一個代理類就可以了。
代理類:
public class CGLIBProcy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); private Object object; public CGLIBProcy(Object object) { this.object = object; } public Object getProxy(){ //設定需要建立子類的類 enhancer.setSuperclass(object.getClass()); enhancer.setCallback(this); //建立代理物件 return enhancer.create(); } // o: cglib 動態生成的代理類的範例 // method:實體類所呼叫的都被代理的方法的參照 // objects 參數列 // methodProxy:生成的代理類對方法的代理參照 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("售前瞭解"); Object invoke = method.invoke(object, objects); System.out.println("售後處理"); return invoke; } }
執行程式碼:
public class Test { public static void main(String[] args) { Mouse logitechMouse = new LogitechMouse(); CGLIBProcy cglibProcy = new CGLIBProcy(logitechMouse); Mouse proxy = (Mouse)cglibProcy.getProxy(); proxy.sell(); cglibProcy = new CGLIBProcy(new HHKBKeyboard()); Keyboard keyboard = (Keyboard)cglibProcy.getProxy(); keyboard.sell(); } }
推薦學習:《》
以上就是完全掌握Java動態代理的詳細內容,更多請關注TW511.COM其它相關文章!