Spring進階之路(10)-Advice簡介以及通過cglib生成AOP代理物件
阿新 • • 發佈:2019-02-19
Advice簡介
1. Before:在目標方法執行之前執行織入,如果Before的處理中沒有進行特殊的處理,那麼目標方法最終會執行,但是如果想要阻止目標方法執行時,可以通過丟擲一個異常來實現,Before處理無法拿到目標方法的返回值,因為這時候目標方法並未執行。
2. AfterReturning: 返回之後執行(前提是目標方法執行成功),可以訪問到目標物件的返回值,但是不可以改變返回值。
3. AfterThrowing:丟擲異常之後執行,可以對異常進行適當的修復或者將異常輸出到日誌中。
4. After:不管目標物件執行成功與否都會被織入常用於釋放資源等。
5. Around:既可以在目標方法之前,又可以在目標方法呼叫之後執行,但是需要線上程安全的情況下執行,如果需要目標方法執行之前或者之後共享某種資料,應該考慮用Around。需要改變返回值的時候,只能使用Around。
通過cglib生成AOP代理物件
上一篇文章中已經提到,通過JDK的代理生成AOP代理物件的方式,但是前提是目標方法實現了介面,如果沒有實現介面的話,那麼怎麼辦?
在這種情況下,我們使用cglib來實現生成AOP代理物件。
定義一個沒有實現介面的User類。
對於Spring而言,如果說目標類實現了介面的話,會按照JDK代理生成AOP代理物件,如果沒有實現介面的話,那麼會使用cglib來生成AOP代理物件。package com.siti.spring20160315; public class User { private String userName; private String password; public User(){} public User(String userName, String password) { super(); this.userName = userName; this.password = password; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void saySth() { System.out.println("hello!"); } }
package com.siti.spring20160315; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.InvocationHandler; public class MyProxy4AOPObject implements InvocationHandler{ private Object targetObj; public Object getProxyObject(Object targetObj){ this.targetObj = targetObj; Enhancer enhance = new Enhancer(); // 將目標類設定為代理物件的父類,產生目標類的子類,這個子類覆蓋所有父類的非final修飾的方法 enhance.setSuperclass(this.targetObj.getClass()); // 設定回撥,可以單獨建立一個類實現InvocationHandler介面實現裡面的invoke方法 enhance.setCallback(this); return enhance.create(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { User user = (User)this.targetObj; Object result = null; try{ // 攔截,符合要求的才允許執行 if(user.getUserName() != null && user.getUserName() != ""){ // -->Before result = method.invoke(this.targetObj, args); // -->AfterReturning } }catch (Exception e) { // -->AfterThrowing }finally{ // -->After } return result; } }
package com.siti.spring20160315;
public class MainTest {
public static void main(String[] args) {
User user = new User("wy", "wy");
MyProxy4AOPObject myProxy4AOPObject = new MyProxy4AOPObject();
User us = (User) myProxy4AOPObject.getProxyObject(user);
us.saySth();
}
}
這裡會輸出:hello!
如果將User中name屬性賦值為null或者""的話就不會輸出,因為在invoke方法中進行了限制,呼叫的目標物件的方法不會執行。