JavaEE - 15反射機制2
阿新 • • 發佈:2020-12-09
JavaEE - 15動態代理2
(7)反射的應用:動態代理
(7.1)代理設計模式原理
- 使用一個代理將物件包裝起來,然後用該代理物件取代原始物件。任何對原始物件的呼叫都要通過代理。
- 代理物件決定是否以及何時將方法呼叫轉到原始物件上。
- 靜態代理,特徵是代理類和目標物件的類都是在編譯期確定下來的,不利於程式擴充套件。
- 每個代理類只能為一個介面服務,這樣一來就比如產生過多的代理。最好可以通過一個代理類完成全部的代理功能。
- 動態代理是指客戶通過代理類來呼叫其他物件的方法,並且是在程式執行時根據需要動態建立目標類的代理物件。
- 動態代理使用場合:
- 除錯
- 遠端方法呼叫
- 動態代理相比於靜態代理的優點
- 抽象角色中(介面)宣告的所有方法都被轉移到呼叫處理器一個集中的方法中處理,這樣,我們可以更加靈活和統一的處理眾多的方法。
(7.2)靜態代理
//--介面 public interface ClothFactory { void productCloth(); } // 代理類-------------------- public class ProxyClothFactory implements ClothFactory { // 用被代理類物件進行例項化 private ClothFactory factory; public ProxyClothFactory(ClothFactory factory){this.factory = factory; } @Override public void productCloth() { System.out.println("代理工廠做準備工作"); factory.productCloth(); System.out.println("代理工廠做收尾工作"); } }
// 被代理類---------------------- public class NikeClothFactory implements ClothFactory{ @Overridepublic void productCloth() { System.out.println("Nike工廠生產Nike運動服"); } }
// 測試---------------------- public class ProxyTest { public static void main(String[] args) { NikeClothFactory nikeClothFactory = new NikeClothFactory(); ProxyClothFactory factory = new ProxyClothFactory(nikeClothFactory); factory.productCloth(); } }
(7.3)動態代理
- 要想實現動態代理,需要解決的問題
- 一是: 如何根據載入到記憶體中的被代理類,動態的建立一個代理類及其物件。
- 二是: 當通過代理類的物件呼叫方法時,如何動態的去呼叫被代理類中的同名方法。
介面及被代理類
public interface Human { String getBelief(); void eat(String food); } //被代理類 ----------- public class SuperMan implements Human { @Override public String getBelief() { return "I can fly"; } @Override public void eat(String food) { System.out.println("吃"+food); } }
MyInvocationHandler
public class MyInvocationHandler implements InvocationHandler { private Object obj; public void bind(Object obj) { this.obj = obj; } // 當我們通過代理類的物件,呼叫方法a時,就會自動的呼叫如下的方法: invoke()
// 將被代理要執行的方法a 的功能宣告在invoke()中。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // method: 代理類物件呼叫的方法,此方法也是被代理類要呼叫的方法 // obj: 被代理類的物件
Object returnValue = method.invoke(obj, args); return returnValue; } }
ProxyFactory代理工廠
public class ProxyFactory { // 呼叫此方法,返回一個代理類的物件,解決問題1 public static Object getProxyInstance(Object obj){ //obj: 被代理類的物件 MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); } }
測試
public class ProxyTest { public static void main(String[] args){ SuperMan superMan = new SuperMan(); // proxyInstance: 代理類的物件 Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); // 當通過代理類物件呼叫方法時,會自動呼叫被代理類中的同名的方法 String belief = proxyInstance.getBelief(); System.out.println(belief); proxyInstance.eat("四川麻辣燙"); System.out.println("-------------------------"); NikeClothFactory nikeClothFactory = new NikeClothFactory(); ClothFactory clothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory); clothFactory.productCloth(); } }
(7.4)動態代理與AOP(Aspect Orient Programming)
- 程式碼段1、程式碼段2、程式碼段3都同時呼叫了特定方法A。
- 理想效果:程式碼段1、2、3既可以執行方法A,又無須在程式中以硬編碼的方式直接呼叫方法A。
- AOP代理方法:
- 動態代理增加的通用方法1
- 回撥目標物件的方法
- 動態代理增加的通用方法2
通用方法類HumanUtil
public class HumanUtil { public void method1(){ System.out.println("========通用方法1=========="); } public void method2(){ System.out.println("========通用方法2=========="); } }
MyInvocationHandler方法改進
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // method: 代理類物件呼叫的方法,此方法也是被代理類要呼叫的方法 // obj: 被代理類的物件 HumanUtil humanUtil = new HumanUtil(); humanUtil.method1(); Object returnValue = method.invoke(obj, args); humanUtil.method2(); return returnValue; }
執行結果:
========通用方法1========== ========通用方法2========== I can fly ========通用方法1========== 吃四川麻辣燙 ========通用方法2==========