第三章、AOP前奏
阿新 • • 發佈:2020-09-16
要求
-
執行加減乘除運算
-
日誌:在程式執行期間追蹤正在發生的活動
-
驗證:希望計算器只能處理正數的運算
@Service public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public void add(int n, int m) { System.out.println("日誌:The Method add begin ["+n+","+m+"]"); int result = n+m; System.out.println("result = " + result); } @Override public void dev(int n, int m) { System.out.println("日誌:The Method dev begin ["+n+","+m+"]"); int result = n-m; System.out.println("result = " + result); } @Override public void mul(int n, int m) { System.out.println("日誌:The Method mul begin ["+n+","+m+"]"); int result = n*m; System.out.println("result = " + result); } @Override public void sub(int n, int m) { System.out.println("日誌:The Method sub begin ["+n+","+m+"]"); int result = n/m; System.out.println("result = " + result); } }
問題
-
程式碼混亂:越來越多的非業務需求(日誌和驗證等)加入後,原有的業務方法急劇膨脹。每個方法在處理核心邏輯的同時還必須兼顧其他多個關注點。
-
程式碼分散: 以日誌需求為例,只是為了滿足這個單一需求,就不得不在多個模組(方法)裡多次重複相同的日誌程式碼。如果日誌需求發生變化,必須修改所有模組。
//生成代理物件 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
newProxyInstance方法中的三個引數
-
第一個引數:類載入器物件,動態載入代理類
-
目標類實現的所有介面,檢視目標物件的方法都來自哪。
-
InvocationHandler介面類的物件
動態代理整個過程是在newProxyInstance
方法中的引數InvocationHandler中完成的,動態代理要做的業務邏輯放在InvocationHandler 的invoke方法中編寫。
public Object invoke(Object proxy, Method method, Object[] args)
invoke方法中的三個引數
-
proxy:代理物件,呼叫代理方法會回過頭呼叫invoke方法。
-
method:正在被呼叫的方法物件
-
args:正在被呼叫的方法引數
代理物件呼叫代理方法會回過頭呼叫invoke方法。
- 業務類
@Service public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int n, int m) { return n+m; } }
- 自定義代理類
public class CalculProxy { //第一步:目標物件 private Object target; public CalculProxy(Object target) { this.target = target; } //第二步:獲取代理物件 public Object getObject(Object obj){ return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { //第三步:代理物件要做什麼 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); System.out.println("日誌:The Method "+name+" begin "+ Arrays.toString(args)); ////相當於執行目標類中的方法(add sub 方法) Object result = method.invoke(target, args); System.out.println(name+":result = " + result); return result; } }); } }
- 測試
@Test public void test_method07() { //第一步:獲取目標物件 ArithmeticCalculatorImpl calculService = new ArithmeticCalculatorImpl(); //第二步:獲取代理物件 CalculProxy calculProxy = new CalculProxy(calculService); ArithmeticCalculator proxy =(ArithmeticCalculator)calculProxy.getObject(calculService); proxy.add(1,2); }