Spring學(xué)習(xí)通過(guò)AspectJ注解方式實(shí)現(xiàn)AOP操作
Spring注解AspectJ操作AOP
一、被增強(qiáng)類(lèi)
新建一個(gè)被增強(qiáng)的類(lèi) User,下面有個(gè) add() 方法。
package com.pingguo.spring5.aopanno; public class User { public void add() { System.out.println("add ... ..."); } }
二、增強(qiáng)類(lèi)
創(chuàng)建增強(qiáng)類(lèi),用于編寫(xiě)增強(qiáng)的邏輯。
package com.pingguo.spring5.aopanno;public class UserProxy { // 前置通知 public void before() { System.out.println("before ... ..."); }}package com.pingguo.spring5.aopanno; public class UserProxy { // 前置通知 public void before() { System.out.println("before ... ..."); } }
三、進(jìn)行通知的配置
1. spring 配置文件中,開(kāi)啟掃描。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--開(kāi)啟注解掃描--> <context:component-scan base-package="com.pingguo.spring5.aopanno"></context:component-scan> <!--開(kāi)啟 Aspect 生成代理對(duì)象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
這里創(chuàng)建了 2 個(gè)名稱(chēng)空間:
xmlns:context:開(kāi)啟注解掃描用
xmlns:aop:開(kāi)啟生成代理對(duì)象
2. 使用注解創(chuàng)建 User 和 UserProxy 對(duì)象
// 被增強(qiáng)類(lèi) @Component public class User { public void add() { System.out.println("add ... ..."); } }
// 增強(qiáng)類(lèi) @Component public class UserProxy { // 前置通知 public void before() { System.out.println("before ... ..."); } }
使用 @Component 注解。
3. 在增強(qiáng)類(lèi)上使用注解 @Aspect
// 增強(qiáng)類(lèi) @Component @Aspect public class UserProxy { // 前置通知 public void before() { System.out.println("before ... ..."); } }
4. spring配置,開(kāi)啟生成代理對(duì)象
<!--開(kāi)啟 Aspect 生成代理對(duì)象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
在配置文件中增加配置。
5. 配置不同類(lèi)型的通知
在上一篇文章中提到了 5 種不同類(lèi)型的通知,在這里使用不同的注解來(lái)配置不同的類(lèi)型。
(1)@Before
表示作為前置通知。
// 增強(qiáng)類(lèi) @Component @Aspect public class UserProxy { // 前置通知 @Before(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void before() { System.out.println("before ... ..."); } }
@Before 注解里的 value 值就是切入點(diǎn)表達(dá)式,表示要對(duì)哪個(gè)類(lèi)里面的哪個(gè)方法進(jìn)行增強(qiáng)。
新建一個(gè)測(cè)試類(lèi)的方法運(yùn)行一下:
public class TestAop { @Test public void testAopanno() { ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add(); } }
運(yùn)行結(jié)果:
before ... ... add ... ... Process finished with exit code 0
可以看出,先執(zhí)行了前置增強(qiáng) before() 方法,再執(zhí)行了 add() 方法。
(2)@After
表示作為后置通知。而且不管有沒(méi)有異常都會(huì)執(zhí)行(文末示例)。
// 后置通知 @After(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void after() { System.out.println("After ... ..."); }
運(yùn)行結(jié)果:
add ... ... After ... ... Process finished with exit code 0
(3)@AfterReturning
另外,還有個(gè)注解 @AfterReturning,也是在被增強(qiáng)之后執(zhí)行,不過(guò)可以拿到被增強(qiáng)方法的返回值。
修改被增強(qiáng)類(lèi)的 add() 方法:
// 被增強(qiáng)類(lèi) @Component public class User { public String add() { System.out.println("add ... ..."); return "add()方法返回值"; } }
修改增強(qiáng)類(lèi):
@AfterReturning(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))", returning = "result") public void afterReturning(String result) { System.out.println("AfterReturning ... ..." + result); }
這里 returning = "result",result 就是定義的獲取到的變量,下面可以使用。
運(yùn)行測(cè)試:
add ... ... AfterReturning ... ...add()方法返回值 Process finished with exit code 0
(4)@Around
表示環(huán)繞通知。
// 環(huán)繞通知 @Around(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環(huán)繞之前 ... ..."); // 被增強(qiáng)的方法執(zhí)行 proceedingJoinPoint.proceed(); System.out.println("環(huán)繞之后 ... ..."); }
運(yùn)行結(jié)果:
環(huán)繞之前 ... ... add ... ... 環(huán)繞之后 ... ... Process finished with exit code 0
(5)@AfterThrowing
表示環(huán)繞通知。
現(xiàn)在讓 add() 方法拋異常:
// 被增強(qiáng)類(lèi) @Component public class User { public void add() { int i = 1/0; System.out.println("add ... ..."); } }
使用 @AfterThrowing:
// 異常通知 @AfterThrowing(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("AfterThrowing ... ..."); }
運(yùn)行測(cè)試:
AfterThrowing ... ... java.lang.ArithmeticException: / by zero
注意,在上面提到的 @After,不管有沒(méi)有異常都會(huì)執(zhí)行。
// 異常通知 @AfterThrowing(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("AfterThrowing ... ..."); } // 后置通知 @After(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void after() { System.out.println("After ... ..."); }
運(yùn)行測(cè)試:
After ... ... AfterThrowing ... ... java.lang.ArithmeticException: / by zero
四、抽取相同切入點(diǎn)
在上述的介紹中,發(fā)現(xiàn)每個(gè)通知里的切入點(diǎn)表達(dá)式都是一樣的,那么可以進(jìn)行抽取。
修改增強(qiáng)類(lèi),使用 @Pointcut :
// 增強(qiáng)類(lèi) @Component @Aspect public class UserProxy { @Pointcut(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void pointDemo() { } // 前置通知 @Before(value = "pointDemo()") public void before() { System.out.println("before ... ..."); } ... ...
使用 @Pointcut 注解把表達(dá)式抽取出來(lái)到方法 pointDemo() 上,后續(xù)的通知里,value = "pointDemo()" 即可。
運(yùn)行測(cè)試:
before ... ... add ... ... Process finished with exit code 0
如果需要改動(dòng)表達(dá)式,只修改這一處就好。
五、多個(gè)增強(qiáng)類(lèi)的優(yōu)先級(jí)
如果有多個(gè)增強(qiáng)類(lèi)對(duì)同一個(gè)方法進(jìn)行增強(qiáng),可以設(shè)置增強(qiáng)類(lèi)的優(yōu)先級(jí)。
給這 2 個(gè)增強(qiáng)類(lèi)添加注解 @Order(1)、 @Order(2),注意,里面的數(shù)值越小,優(yōu)先級(jí)越高。
新建的增強(qiáng)類(lèi) PersonProxy:
// 新建另一個(gè)增強(qiáng)類(lèi) @Component @Aspect @Order(1) public class PersonProxy { @Pointcut(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void pointDemo() { } // 前置通知 @Before(value = "pointDemo()") public void before() { System.out.println("PersonProxy 類(lèi)的 before ... ..."); } }
之前的 增強(qiáng)類(lèi):
// 增強(qiáng)類(lèi) @Component @Aspect @Order(2) public class UserProxy { @Pointcut(value = "execution(* com.pingguo.spring5.aopanno.User.add(..))") public void pointDemo() { } // 前置通知 @Before(value = "pointDemo()") public void before() { System.out.println("before ... ..."); }
運(yùn)行測(cè)試:
PersonProxy 類(lèi)的 before ... ... before ... ... add ... ... Process finished with exit code 0
Order(1) 的增強(qiáng)了 PersonProxy 下的通知先執(zhí)行。
以上就是Spring學(xué)習(xí)通過(guò)AspectJ注解方式實(shí)現(xiàn)AOP操作的詳細(xì)內(nèi)容,更多關(guān)于Spring注解AspectJ操作AOP的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
自定義Spring Security的身份驗(yàn)證失敗處理方法
在本篇文章里小編給大家整理了一篇關(guān)于自定義Spring Security的身份驗(yàn)證失敗的處理方法,有需要的朋友們學(xué)習(xí)下。2019-05-05MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決
這篇文章主要介紹了MyBatis使用<foreach>標(biāo)簽報(bào)錯(cuò)問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03JAVA簡(jiǎn)單選擇排序算法原理及實(shí)現(xiàn)
選擇排序(Selection Sort )分為兩種 簡(jiǎn)單選擇排序(Simple Selection Sort) 和樹(shù)形選擇排序2014-01-01springboot實(shí)現(xiàn)單文件和多文件上傳
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)單文件和多文件上傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11歸并排序時(shí)間復(fù)雜度過(guò)程推導(dǎo)詳解
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)排序算法之歸并排序,對(duì)歸并排序的原理及實(shí)現(xiàn)過(guò)程做了非常詳細(xì)的解讀,需要的朋友可以參考下,希望能幫助到你2021-08-08通過(guò)實(shí)例解析java8中的parallelStream
這篇文章主要介紹了通過(guò)實(shí)例解析java8中的parallelStream,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Java實(shí)現(xiàn)Kafka生產(chǎn)者消費(fèi)者代碼實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)Kafka生產(chǎn)者消費(fèi)者代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04JDK8接口的默認(rèn)與靜態(tài)方法-接口與抽象類(lèi)的區(qū)別詳解
這篇文章主要介紹了JDK8接口的默認(rèn)與靜態(tài)方法-接口與抽象類(lèi)的區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下2019-06-06