如何使用Spring AOP的通知類型及創(chuàng)建通知
寫在最前端
1.SpringAOP中共有六種通知類型,只要我們自定義一個(gè)類實(shí)現(xiàn)對(duì)應(yīng)的接口,它們?nèi)际莖rg.springframework.aop包中的。
2.AOP的連接點(diǎn)可以是方法調(diào)用、方法調(diào)用本身、類初始化、對(duì)象實(shí)例化時(shí),但是SpringAOP中全是方法調(diào)用,更簡(jiǎn)單,也最實(shí)用
通知名稱 | 接口 |
---|---|
前置通知 | org.springframework.aop.MethodBeforeAdvice |
后置返回通知 | org.springframework.aop.AfterReturningAdvice |
后置通知 | org.springframework.aop.AfterAdvice |
環(huán)繞通知 | org.springframework.aop.MethodInterceptor |
異常通知 | org.springframework.aop.ThrowsAdvice |
引入通知 | org.springframework.aop.IntroductionInterceptor |
寫一個(gè)公共類,用于目標(biāo)對(duì)象
public class Person { private String name; public boolean saySomething(String something){ System.out.println("Pereson類中說(shuō)了一句:"+something); return true;//默認(rèn)返回true } public String getName() { return name; } public void setName(String name) { this.name = name; } }
一、創(chuàng)建前置通知(也就是目標(biāo)方法調(diào)用前執(zhí)行)
前置通知可以修改傳遞給方法的參數(shù),并且可以通過(guò)拋出異常來(lái)阻止方法的執(zhí)行,可以用前置通知實(shí)現(xiàn)用戶登錄的驗(yàn)證,SpringSecurity就是這么做的
1.例子:在一個(gè)方法執(zhí)行前將包含方法名稱的消息寫入到控制臺(tái)中,并且將傳入的參數(shù)修改下。(文章中寫的內(nèi)容比較小,大多數(shù)在代碼中有注釋,大家可以下載代碼查看)
/** * 前置通知類 */ public class BeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable { //第一個(gè)參數(shù)是目標(biāo)方法對(duì)象,第二個(gè)是參數(shù),第三個(gè)是做為調(diào)用目標(biāo)的object(這是personr實(shí)例) //打印方法名 System.out.println("要執(zhí)行的方法是:"+method.getName()); //修改參數(shù)為lyn4ever objects[0]="lyn4ever";//我們修改成為了lyn4ever,所以打印出來(lái)的就是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(); //我這里傳的參數(shù)是zhangsan,理論上它應(yīng)該打印出來(lái)zhangsan proxy.saySomething("zhangsan"); } }
沒(méi)毛病,本來(lái)我輸入的是zhangsan,在aop中將參數(shù)改為了lyn4ever,這樣就完美的替換了。
二、后置返回通知
是在連接點(diǎn)(方法調(diào)用)返回后執(zhí)行,這顯然不能像上邊那樣修改參數(shù),也不能修改返回值。但是可以拋出可以發(fā)送到堆棧的異常,同樣也可以調(diào)用其他方法。
/** * 后置返回通知 */ public class AfterReturnAdvice implements AfterReturningAdvice { @Override public void afterReturning(@Nullable Object o, Method method, Object[] objects, @Nullable Object o1) throws Throwable { /* 參數(shù)和前置通知是一樣的 這個(gè)是在返回之后調(diào)用,因此,person中的saySomething會(huì)先打印,我們?cè)谶@里修改的參數(shù)不起作任何作用 */ System.out.println("調(diào)用的方法是:"+method.getName()+"這句是在saySomething之后");//這句是在saySomething之后 objects[0]="lyn4ever";//這句可以修參數(shù),但是之前的方法已經(jīng)執(zhí)行過(guò)了,所以不起任何作用 System.out.println("我們修改了參數(shù)為:"+objects[0]+"但是沒(méi)有任何用");//這時(shí)候這個(gè)參數(shù)并不會(huì)傳到person.saysomething(),因?yàn)橐呀?jīng)調(diào)用過(guò)了 } public static void main(String[] args) { Person person = new Person(); ProxyFactory pf = new ProxyFactory(); pf.addAdvice(new AfterReturnAdvice());//注意修改這個(gè)為當(dāng)前類中的通知類 pf.setTarget(person); Person proxy = (Person) pf.getProxy(); proxy.saySomething("zhangsan"); } }
三、環(huán)繞通知
這人最好理解了,就是在方法調(diào)用前后都可以執(zhí)行代碼??雌饋?lái)像是前置后后置的集合,但是它可以修改方法的返回值,因?yàn)樗鼘?shí)現(xiàn)的invoke方法的返回值是Object,所以我們就可以修改,而前置通知的返回是void,所以沒(méi)法修改的。甚至以至于我們可以不調(diào)用目標(biāo)對(duì)象中的連接點(diǎn)方法,我們完全修改這個(gè)方法的全部代碼。
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { return null; } }
雖然這個(gè)invoke()方法中并沒(méi)有提供像之前的那些參數(shù),但是這一個(gè)invocation實(shí)例可以得到
代碼示例
/** * 環(huán)繞通知 */ public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { //在這個(gè)invoation中有一切我們想要的方法相關(guān) System.out.println("類名是:"+invocation.getThis().getClass().getName()); System.out.println("目標(biāo)方法是:"+invocation.getMethod().getName()); Object[] arguments = invocation.getArguments();//這個(gè)就是參數(shù) System.out.println("第一個(gè)參數(shù) 是:"+arguments[0]); //我們修改第一個(gè)參數(shù)為lyn4ever arguments[0]="lyn4ever"; invocation.proceed();//執(zhí)行目標(biāo)方法 System.out.println("這個(gè)是在之后執(zhí)行的"); return false;//修改返回值 } public static void main(String[] args) { Person person = new Person(); ProxyFactory pf = new ProxyFactory(); pf.addAdvice(new MyMethodInterceptor());//注意修改這個(gè)為當(dāng)前類中的通知類 pf.setTarget(person); Person proxy = (Person) pf.getProxy(); boolean flag = proxy.saySomething("zhangsan"); System.out.println(flag);//方法本來(lái)是要返回true的 } }
可以看到,我們修改了目標(biāo)方法返回的值。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
簡(jiǎn)單的理解java集合中的HashSet和HashTree幾個(gè)重寫方法
這篇文章主要介紹了簡(jiǎn)單的理解java集合中的HashSet和HashTree幾個(gè)重寫方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10利用微信小程序+JAVA實(shí)現(xiàn)微信支付的全過(guò)程
微信支付是一種在線支付解決方案,允許用戶通過(guò)微信內(nèi)的支付功能進(jìn)行付款,下面這篇文章主要給大家介紹了關(guān)于利用微信小程序+JAVA實(shí)現(xiàn)微信支付的相關(guān)資料,需要的朋友可以參考下2024-08-08Java分布式鎖理論(redis、zookeeper))案例詳解
zookeeper有個(gè)節(jié)點(diǎn)路徑的概念,節(jié)點(diǎn)路徑不能重復(fù),保證了唯一性,這篇文章給大家介紹Java分布式鎖理論(redis、zookeeper)?案例詳解,感興趣的朋友跟隨小編一起看看吧2024-01-01springboot跨域過(guò)濾器fetch react Response to p
這篇文章主要介紹了springboot跨域過(guò)濾器fetch react Response to preflight request doesn‘t pass access control check問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03