一.SpringAOP的概述。 AOP(Aspect Oriented Programming),面向切麵編程,通過預編譯方式和運行期間動態代理實現程式的功能的統一維護的技術。AOP是OOP(面向對象編程)的擴展和延伸。舉個例子,讓大家對AOP印象更加深刻點。 比如許可權校驗。實際開發中,我們知道不是 ...
一.SpringAOP的概述。
AOP(Aspect Oriented Programming),面向切麵編程,通過預編譯方式和運行期間動態代理實現程式的功能的統一維護的技術。AOP是OOP(面向對象編程)的擴展和延伸。舉個例子,讓大家對AOP印象更加深刻點。
比如許可權校驗。實際開發中,我們知道不是所有人都可以進行增刪改查的操作,只有管理員才可以,所以我們需要在進行增刪改查之前都需要進行許可權校驗。傳統縱向繼承(面向對象的特征)就是定義一個BaseDao,裡面含有一個許可權校驗的方法,讓Dao直接繼承
BaseDao,這樣就可以直接調用Dao父類中的許可權校驗方法。而AOP則採用的是橫向抽取機制替代了傳統的縱向繼承,也就是通過生成代理的方式來解決。這就是對方法進行擴展的兩個方法的思想。
AOP應用:許可權校驗,日誌記錄,性能監控(運用代理,分別在代碼前後插入記錄時間),事務控制
二.Spring底層實現AOP的原理。
底層用到了兩種代理機制:
JDK動態代理:針對實現了介面的類的代理(java基礎的代理)。
Cglib的動態代理:針對沒有實現介面的類產生的代理,底層用的是位元組碼增強技術,通過生成當前類的子對象來產生代理。
被代理類
public class UserDaoImpl implements UserDao { @Override public void insert() { System.out.println("用戶增加...."); } @Override public void remove() { System.out.println("用戶移除...."); } }
JDK動態代理:
public class MyJDKProxy implements InvocationHandler { // 定義屬性,傳入實現類對象,也可以不用,但是後面就要用類名,而不是引用 private UserDaoImpl userDao; public MyJDKProxy(UserDaoImpl userDao) { this.userDao = userDao; } // 創建UserDao動態代理 public UserDao createUserProxy() { /* * 第一個參數。告訴虛擬機用哪個位元組碼載入器載入記憶體創建位元組碼文件。 * 第二個參數。告訴虛擬機記憶體中創建的位元組碼文件中應該有哪個方法(這些方法方法體為空)。獲取類的介面(類的方法可能增加,但介面的方法是固定的) * 第三個參數。告訴虛擬機底層正在創建的位元組碼上的各個方法如何處理。 * */ UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(MyJDKProxy.class.getClassLoader(), userDao.getClass().getInterfaces(), this); return userDaoProxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equalsIgnoreCase("insert")) { System.out.println("許可權校驗"); } // 執行被代理類原有的方法 return method.invoke(userDao, args); } }
運行結構
許可權校驗
用戶增加....
Cglib的父類:
public class CustDao { public void remove() { System.out.println("顧客移除"); } }
Cglib動態代理:
public class MyCglibProxy { public CustDao createProxy() { // 創建cglib和心類 Enhancer enhancer = new Enhancer(); // 設置父類 enhancer.setSuperclass(CustDao.class); // 設置回調 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if("remove".equalsIgnoreCase(method.getName())) { // 執行被代理父類的方法 Object obj = methodProxy.invokeSuper(proxy, args); System.out.println("日誌記錄"); return obj; } return methodProxy.invokeSuper(proxy, args); } }); // 生成代理 CustDao custDao = (CustDao) enhancer.create(); return custDao; } }
運行結果:
許可權校驗
用戶增加....
顧客移除
日誌記錄