(13)Spring學習記錄---Spring_bean(AOP基礎)
阿新 • • 發佈:2018-11-08
先來實現一個例項
1.建立介面ArithmeticCalulator
public interface ArtithmeticCaclulator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
2.實現ArithmeticCalulatorImpl,並加入日誌資訊
public class ArithmeticCalulatorImpl implements ArtithmeticCaclulator { @Override public int add(int i, int j) { System.out.println("The method add begin with [" + i + "," + j + "]"); int result = i + j; System.out.println("The method add end with " + result); return result; } @Override public int sub(int i, int j) { System.out.println("The method sub begin with [" + i + "," + j + "]"); int result = i - j; System.out.println("The method sub end with " + result); return result; } @Override public int mul(int i, int j) { System.out.println("The method mul begin with [" + i + "," + j + "]"); int result = i * j; System.out.println("The method mul end with " + result); return result; } @Override public int div(int i, int j) { System.out.println("The method div begin with [" + i + "," + j + "]"); int result = i / j; System.out.println("The method div end with " + result); return result; } }
3.Main
public class Main { public static void main(String[] args) { ArtithmeticCaclulator artithmeticCaclulator =new ArithmeticCalulatorImpl(); int result=artithmeticCaclulator.add(1, 2); System.out.println("->>"+result); result=artithmeticCaclulator.sub(3, 2); System.out.println("->>"+result); } }
4.結果
可以看到這些日記資訊都十分相似,而且當我加入這些日誌資訊後,有時候會和業務程式碼混淆,難以區分。不利於我們的維護。
解決方法一:
1.動態代理
AritimeticCalulatorLoggingProxy.class
public class AritimeticCalulatorLoggingProxy { //要代理的物件 private ArtithmeticCaclulator target; public AritimeticCalulatorLoggingProxy(ArtithmeticCaclulator target) { this.target = target; } public ArtithmeticCaclulator getLoggingProxy() { ArtithmeticCaclulator proxy=null; //代理物件由哪個類載入器載入 ClassLoader loader=target.getClass().getClassLoader(); //代理物件的型別 包括其中的方法 Class [] interfaces =new Class[] {ArtithmeticCaclulator.class}; //當呼叫代理物件的方法時 指向的程式碼 InvocationHandler h =new InvocationHandler() { /** * proxy:正在返回的那個代理物件 一般情況下 在invoke方法總都不使用該物件 * method:正在被呼叫的方法 * args:呼叫方法的引數 * **/ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodname=method.getName(); //日誌 System.out.println("The method "+ methodname +" begin with "+ Arrays.asList(args)); //執行方法 Object result = method.invoke(target, args); //日誌 System.out.println("The method "+ methodname + " end with " + result); return result; } }; proxy=(ArtithmeticCaclulator)Proxy.newProxyInstance(loader, interfaces, h); return proxy; } }
我們把公共程式碼寫在InvocationHandler裡面。同時去除ArithmeticCalulatorImpl的日誌資訊。
修改Main方法 ,通過代理呼叫方法
public class Main {
public static void main(String[] args) {
ArtithmeticCaclulator target=new ArithmeticCalulatorImpl();
ArtithmeticCaclulator proxy= new AritimeticCalulatorLoggingProxy(target).getLoggingProxy();
int result=proxy.add(1, 2);
System.out.println("->>"+result);
result=proxy.sub(3, 2);
System.out.println("->>"+result);
}
}
結果:
我們可以引入這樣一種思想,將業務程式碼和日誌程式碼以某種形式分離開來,由於他們是同一層的(橫向的),所有我們可以像上面的例子用Proxy分離。但是實際中肯定不能這麼做,一是維護成本高,二是對程式設計師要求也高。
我們可以利用Aop程式設計的思想來解決程式碼分離的問題。
AOP簡介
術語
1.切面:我們將日誌抽取出來,作為一個切面,將驗證抽取出來,作為一個切面,將業務邏輯抽取出來,作為一個切面。這些切面都叫做橫切關注點。
2.通知:切面裡的每一個方法都是一個通知。它是每個切面必須完成的工作。
3.目標:被通知的物件,這裡是add(),mul(),div(),sub()。
4.代理:通知目標後,業務邏輯和日誌必須有一個結合,這樣的結果就是產生一個代理。
5.連線點:以方法執行為評判標準,執行前後中,異常丟擲時等等。。相當於一個被查詢的資料。是切點的定位目標
6.切點:aop通過切點定位到連線點,看不見摸不著。相當於查詢條件。