如何使用Spring AOP的通知型別及建立通知
寫在最前端
1.SpringAOP中共有六種通知型別,只要我們自定義一個類實現對應的介面,它們全都是org.springframework.aop包中的。
2.AOP的連線點可以是方法呼叫、方法呼叫本身、類初始化、物件例項化時,但是SpringAOP中全是方法呼叫,更簡單,也最實用
通知名稱 | 介面 |
---|---|
前置通知 | org.springframework.aop.MethodBeforeAdvice |
後置返回通知 | org.springframework.aop.AfterReturningAdvice |
後置通知 | org.springframework.aop.AfterAdvice |
環繞通知 | org.springframework.aop.MethodInterceptor |
異常通知 | org.springframework.aop.ThrowsAdvice |
引入通知 | org.springframework.aop.IntroductionInterceptor |
寫一個公共類,用於目標物件
public class Person { private String name; public boolean saySomething(String something){ System.out.println("Pereson類中說了一句:"+something); return true;//預設返回true } public String getName() { return name; } public void setName(String name) { this.name = name; } }
一、建立前置通知(也就是目標方法呼叫前執行)
前置通知可以修改傳遞給方法的引數,並且可以通過丟擲異常來阻止方法的執行,可以用前置通知實現使用者登入的驗證,SpringSecurity就是這麼做的
1.例子:在一個方法執行前將包含方法名稱的訊息寫入到控制檯中,並且將傳入的引數修改下。(文章中寫的內容比較小,大多數在程式碼中有註釋,大家可以下載程式碼檢視)
/** * 前置通知類 */ public class BeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method,Object[] objects,@Nullable Object o) throws Throwable { //第一個引數是目標方法物件,第二個是引數,第三個是做為呼叫目標的object(這是personr例項) //列印方法名 System.out.println("要執行的方法是:"+method.getName()); //修改引數為lyn4ever objects[0]="lyn4ever";//我們修改成為了lyn4ever,所以打印出來的就是lyn4ever,而不是zhangsan } public static void main(String[] args) { Person person = new Person(); ProxyFactory pf =new ProxyFactory(); pf.addAdvice(new BeforeAdvice()); pf.setTarget(person); Person proxy = (Person) pf.getProxy(); //我這裡傳的引數是zhangsan,理論上它應該打印出來zhangsan proxy.saySomething("zhangsan"); } }
沒毛病,本來我輸入的是zhangsan,在aop中將引數改為了lyn4ever,這樣就完美的替換了。
二、後置返回通知
是在連線點(方法呼叫)返回後執行,這顯然不能像上邊那樣修改引數,也不能修改返回值。但是可以丟擲可以傳送到堆疊的異常,同樣也可以呼叫其他方法。
/** * 後置返回通知 */ public class AfterReturnAdvice implements AfterReturningAdvice { @Override public void afterReturning(@Nullable Object o,Method method,@Nullable Object o1) throws Throwable { /* 引數和前置通知是一樣的 這個是在返回之後呼叫,因此,person中的saySomething會先列印,我們在這裡修改的引數不起作任何作用 */ System.out.println("呼叫的方法是:"+method.getName()+"這句是在saySomething之後");//這句是在saySomething之後 objects[0]="lyn4ever";//這句可以修引數,但是之前的方法已經執行過了,所以不起任何作用 System.out.println("我們修改了引數為:"+objects[0]+"但是沒有任何用");//這時候這個引數並不會傳到person.saysomething(),因為已經呼叫過了 } public static void main(String[] args) { Person person = new Person(); ProxyFactory pf = new ProxyFactory(); pf.addAdvice(new AfterReturnAdvice());//注意修改這個為當前類中的通知類 pf.setTarget(person); Person proxy = (Person) pf.getProxy(); proxy.saySomething("zhangsan"); } }
三、環繞通知
這人最好理解了,就是在方法呼叫前後都可以執行程式碼。看起來像是前置後後置的集合,但是它可以修改方法的返回值,因為它實現的invoke方法的返回值是Object,所以我們就可以修改,而前置通知的返回是void,所以沒法修改的。甚至以至於我們可以不呼叫目標物件中的連線點方法,我們完全修改這個方法的全部程式碼。
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { return null; } }
雖然這個invoke()方法中並沒有提供像之前的那些引數,但是這一個invocation例項可以得到
程式碼示例
/** * 環繞通知 */ public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { //在這個invoation中有一切我們想要的方法相關 System.out.println("類名是:"+invocation.getThis().getClass().getName()); System.out.println("目標方法是:"+invocation.getMethod().getName()); Object[] arguments = invocation.getArguments();//這個就是引數 System.out.println("第一個引數 是:"+arguments[0]); //我們修改第一個引數為lyn4ever arguments[0]="lyn4ever"; invocation.proceed();//執行目標方法 System.out.println("這個是在之後執行的"); return false;//修改返回值 } public static void main(String[] args) { Person person = new Person(); ProxyFactory pf = new ProxyFactory(); pf.addAdvice(new MyMethodInterceptor());//注意修改這個為當前類中的通知類 pf.setTarget(person); Person proxy = (Person) pf.getProxy(); boolean flag = proxy.saySomething("zhangsan"); System.out.println(flag);//方法本來是要返回true的 } }
可以看到,我們修改了目標方法返回的值。
本文demo已提交至github
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對我們的支援。