spring框架的核心之一AOP,面向切面編程是一種編程思想。我對於面向切面編程的理解是:可以讓我們動態的控制程序的執行流程及執行結果。spring框架對AOP的實現是為了使業務邏輯之間實現分離,分離主業務邏輯及次要業務邏輯,進而降低系統間的耦合度。
spring框架對於這種編程思想的實現基於兩種動態代理模式,分別是 JDK動態代理 及 CGLIB的動態代理,這兩種動態代理的區別是 JDK動態代理需要目標對象實現接口,而 CGLIB的動態代理則不需要。下面我們通過一個實例來實現動態代理,進而幫助我們理解面向切面編程。
需求:實現一個除法運算器,要求計算出兩個整數相除的商,其中除數為0時提示用戶"除數不能為零"並返回-1,被除數為0零時直接返回0。
我們來看一下一般的做法。
public int division(int a,int b){ if(b == 0){ System.out.println("除數不能為0"); return -1; }else if(a == 0){ return 0; }else{ return a/b; } }
我們來分析一下需求,“計算出兩個整數相除的商”是我們的主業務邏輯,而“除數為0時提示用戶"除數不能為零"並返回-1,被除數為0零時直接返回0”是我們的次要業務邏輯,以上的做法無疑是吧,主業務邏輯和次要業務邏輯偶合到了一塊。這里只是做了一個除法,可當你的主業務邏輯本身就就比價復雜的,再這樣做的話就會增加代碼的偶合度及可讀性。
下面我們使用 JDK的 動態代理來實現以上的需求,雖然以下的做法看起來像是殺雞用牛刀,但我們這里只是為了說明問題。
JDK的動態代理要使用到一個類 Proxy 用於創建動態代理的對象,一個接口 InvocationHandler用於監聽代理對象的行為,其實動態代理的本質就是對代理對象行為的監聽。
首先我們需要提供一個主業務邏輯的接口,這 JDK動態代理實現的先決條件。
public interface IDivisionService { int division(int a ,int b); }
下面是實現類(實現類中只有主頁業務邏輯)
public class DivisionServiceImpl implements IDivisionService { @Override public int division(int a, int b) { return a/b; } }
下面我們來看一下動態代理是怎么分離主業務邏輯和次要業務邏輯的。
首先准備一個創建代理對象的工廠類
public class BeanFactory { public static Object getAgencyObj(final Object target){ Object agencyObj = null; agencyObj = Proxy.newProxyInstance( //獲取目標對象類的加載器 target.getClass().getClassLoader(), //獲取對象接口的Class對象數組 target.getClass().getInterfaces(), //一個內部類,用於創建監聽對象 new InvocationHandler() { /** * 通過反射機制獲得實現類中方法的實例 method 及方法的參數 args 這取決於代理對象 agencyObj調用了那個方法。 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { int a = (int)args[0]; int b = (int)args[1]; //用於處理次要業務邏輯 if(b == 0){ System.out.println("除數不能為0"); return -1; } //用於處理次要業務邏輯 if(a == 0){ return 0; } //執行主業務邏輯 Object result = method.invoke(target, args); return result; } }); return agencyObj; } }
最后測試類:
public class MyTest { public static void main(String[] args) { //創建目標類 IDivisionService target = new DivisionServiceImpl(); //創建代理對象 IDivisionService agencyObj = (IDivisionService)BeanFactory.getAgencyObj(target); int consult = agencyObj.division(0, 2); System.out.println("兩數相除商為--->"+consult); } }
在這里我們看到,除法計算器的實現類DivisionServiceImpl 只是來做除法這一主業務邏輯,而 “除數為0時提示用戶"除數不能為零"並返回-1,被除數為0零時直接返回0”這一次要業務邏輯交由JDK的動態代理來實現。
最后說一點,我們作為程序員,研究問題還是要仔細深入一點的。當你對原理了解的有夠透徹,開發起來也就得心應手了,很多開發中的問題和疑惑也就迎刃而解了,而且在面對其他問題的時候也可做到觸類旁通。當然在開發中沒有太多的時間讓你去研究原理,開發中要以實現功能為前提,可等項目上線的后,你有大把的時間或者空余的時間,你大可去刨根問底,深入的去研究一項技術,為覺得這對一名程序員的成長是很重要的事情。