基于AspectJ注解方式實(shí)現(xiàn)AOP
基于AspectJ實(shí)現(xiàn)AOP(注解方式)
這里我們采用的是非完全注解方式
1. 創(chuàng)建類, 在類里面定義方法(連接點(diǎn))
package com.ffyc.spring.aop; //被增強(qiáng)的類(也就是被代理的類) public class User { //被增強(qiáng)的方法(也就是被代理的方法) public void add(){ System.out.println("add..."); } }
2. 創(chuàng)建增強(qiáng)類, 編寫增強(qiáng)邏輯
- 注意: 此時我們并沒有給增強(qiáng)類添加注解來生成代理對象, 也沒有配置通知(增強(qiáng)的邏輯)
package com.ffyc.spring.aop; //增強(qiáng)類 public class UserProxy { //前置通知 public void before(){ System.out.println("before"); } //這里還有后置通知, 異常通知, 環(huán)繞通知, 最終通知等, 現(xiàn)在邏輯先省略 }
3. 進(jìn)行通知的配置
①: 在spring配置文件中, 開啟注解掃描與開啟注解自動生成代理對象
- 注解掃描大家都知道: 就是componentScan
- 注解自動生成代理對象是什么?
- 就是開啟了注解自動生成代理對象之后當(dāng)SpringIOC容器掃描basePackages的時候如果掃描到某個類上面有@Aspect注解, 則會生成該類的代理對象放到SpringIOC容器中由SpringIOC容器管理
- 所以@Aspect注解就是在增強(qiáng)(通知)類上添加的
- 就是開啟了注解自動生成代理對象之后當(dāng)SpringIOC容器掃描basePackages的時候如果掃描到某個類上面有@Aspect注解, 則會生成該類的代理對象放到SpringIOC容器中由SpringIOC容器管理
<!-- 開啟組件掃描, 開啟了組件掃描之后我們的spring容器就會在對應(yīng)的base-package位置進(jìn)行一個掃描--> <!-- 注意: 其實(shí)我們的組件掃描也是可以通過使用注解的方式進(jìn)行配置--> <context:component-scan base-package="com.ffyc.spring"></context:component-scan> <!-- 開啟Aspectj自動生成代理對象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
②: 使用注解創(chuàng)建User和UserProxy類的對象
- 也就是讓SpringIOC容器幫我們創(chuàng)建
- 在User類和UserProxy類上加上@Component注解即可
package com.ffyc.spring.aop; import org.springframework.stereotype.Component; //被增強(qiáng)的類(也就是被代理的類) @Component public class User { //被增強(qiáng)的方法(也就是被代理的方法) public void add(){ System.out.println("add..."); } }
package com.ffyc.spring.aop; import org.springframework.stereotype.Component; //增強(qiáng)類 @Component public class UserProxy { //前置通知 public void before(){ System.out.println("before"); } }
③: 在增強(qiáng)類上面添加注解@Aspect
- 這里注意: @Aspect注解要和@Component注解一起使用, 原因在最后
package com.ffyc.spring.aop; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; //增強(qiáng)類 @Component @Aspect public class UserProxy { //前置通知 public void before(){ System.out.println("before"); } }
4. 配置不同類型的通知
- 在增強(qiáng)類里面, 在作為通知的方法上面添加對應(yīng)的通知類型的注解, 并使用切入點(diǎn)表達(dá)式將對應(yīng)的通知配置到某個切入點(diǎn)上
- 這樣Spring底層就會幫我們根據(jù)我們添加的注解來創(chuàng)建代理對象
package com.ffyc.spring.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //增強(qiáng)類 @Component @Aspect public class UserProxy { @Pointcut(value = "execution(* com.ffyc.spring.aop.User.add(..))") private void method(){ } //前置通知 @Before(value = "execution (* com.ffyc.spring.aop.User.add(..))") public void before(){ System.out.println("before..."); } @AfterReturning(value = "method()") public void afterReturning(){ System.out.println("afterReturning..."); } @After(value = "execution(* com.ffyc.spring.aop.User.add(..))") public void after(){ System.out.println("after..."); } @AfterThrowing(value = "method()") public void afterThrowing(){ System.out.println("afterThrowing..."); } @Around(value = "method()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環(huán)繞前..."); proceedingJoinPoint.proceed(); System.out.println("環(huán)繞之后..."); } }
- @PointCut注解用來創(chuàng)建一個切入點(diǎn), 該注解的value屬性(String類型)為切入點(diǎn)表達(dá)式
- @Around, @Before, @After, @AfterReturning, @AfterThrowing注解的value屬性(String類型)都為切入點(diǎn)表達(dá)式
- @AfterThrowing針對的是被代理方法拋出異常, 如果異常在內(nèi)部被解決, 那么并不會執(zhí)行@AfterThrowing通知
- 我們通過JVM的學(xué)習(xí)可以知道, 如果方法是通過異常結(jié)束(指拋出異常), 那么肯定就不是正常退出(return), 那么也就意味著@AfterReturning(后置通知), 和@AfterThrowing(異常通知)只能同時觸發(fā)一個
- @Around注解使用的時候要在參數(shù)位置預(yù)留一個ProceedingJoinPoint類型的參數(shù), 最終會通過這個通知類構(gòu)建一個被代理類的代理對象, 這個代理對象是由Spring幫我們創(chuàng)建的, 所以這個通知類也是Spring容器幫我們?nèi)呙璧? 對應(yīng)的@Around注解標(biāo)注的方法肯定也是由Spring幫我們調(diào)用的, 而Spring調(diào)用的方法我們可以在參數(shù)位置寫一個形參, 這個時候Spring默認(rèn)會對該參數(shù)類型進(jìn)行一個自動裝配(基于類型的自動裝配), 這里就會由Spring幫我們裝配一個ProceedingJoinPoint對象, 我們可以調(diào)用其中的proceed()方法, 調(diào)用proceed()方法就會執(zhí)行切入點(diǎn)方法(被增強(qiáng)的方法)
- ProceedingJoinPoint : 正在進(jìn)行的連接點(diǎn)
5. 測試:
package com.ffyc.spring.aop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAop { @Test public void testAop(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); User user = applicationContext.getBean("user", User.class); System.out.println(user); user.add(); } }
- 當(dāng)我們調(diào)用user對象的add()方法的時候其實(shí)會執(zhí)行代理對象的add()方法
各個通知的執(zhí)行順序:
環(huán)繞前[@Around(前)] --> 前置通知[@Before] --> 被增強(qiáng)方法(切入點(diǎn)) --> 環(huán)繞后(@Around(后)) --> 最終通知(@After) --> 后置通知[@AfterReturning] (或者異常通知[@AfterThrowing])
補(bǔ)充:
@Aspect注解為什么要和@Component注解一起使用, 按理將使用一個@Aspect注解不是就已經(jīng)是由SpringIOC榮IQ創(chuàng)建代理對象并交由SpringIOC容器管理了?
**官方文檔解釋如下: **
You may register aspect classes as regular beans in your Spring XML configuration, or autodetect them through classpath scanning - just like any other Spring-managed bean. However, note that the @Aspect annotation is not sufficient for autodetection in the classpath: For that purpose, you need to add a separate @Component annotation (or alternatively a custom stereotype annotation that qualifies, as per the rules of Spring’s component scanner).
翻譯:
您可以在Spring XML配置中注冊aspect類,或者通過類路徑掃描自動檢測它們,就像任何其他Spring管理bean一樣。但是,請注意,@aspect注釋對于在類路徑中自動檢測是不夠的:為了達(dá)到這個目的,您需要添加一個單獨(dú)的@component注解(或者根據(jù)Spring的組件掃描器的規(guī)則來定義一個定制的原型注解)
到此這篇關(guān)于基于AspectJ注解方式實(shí)現(xiàn)AOP的文章就介紹到這了,更多相關(guān)AspectJ實(shí)現(xiàn)AOP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 反轉(zhuǎn)帶頭結(jié)點(diǎn)的單鏈表并顯示輸出的實(shí)現(xiàn)過程
這篇文章主要介紹了Java 反轉(zhuǎn)帶頭結(jié)點(diǎn)的單鏈表并顯示輸出,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-11-11最全JVM調(diào)優(yōu)步驟和參數(shù)及配置
這篇文章主要給大家介紹了關(guān)于JVM調(diào)優(yōu)的相關(guān)資料,JVM調(diào)優(yōu)是指對Java虛擬機(jī)(JVM)進(jìn)行優(yōu)化,以提高Java程序的性能和運(yùn)行效率,文中介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03一篇超詳細(xì)的Spring Boot整合Mybatis文章
大家都知道springboot搭建一個spring框架只需要秒秒鐘。下面通過實(shí)例代碼給大家介紹一下springboot與mybatis的完美融合,非常不錯,具有參考借鑒價值,感興趣的朋友一起看看吧2021-07-07JavaFX程序初次運(yùn)行創(chuàng)建數(shù)據(jù)庫并執(zhí)行建表SQL詳解
這篇文章主要介紹了JavaFX程序初次運(yùn)行創(chuàng)建數(shù)據(jù)庫并執(zhí)行建表SQL詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-08-08SpringBoot 配合 SpringSecurity 實(shí)現(xiàn)自動登錄功能的代碼
這篇文章主要介紹了SpringBoot 配合 SpringSecurity 實(shí)現(xiàn)自動登錄功能的代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09關(guān)于Springboot2.x集成lettuce連接redis集群報超時異常Command timed out afte
這篇文章主要介紹了Springboot2.x集成lettuce連接redis集群報超時異常Command timed out after 6 second(s),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-03-03