寄語:剛開始學aop的時候是大三吧,老師講的不好,我也沒學好,導致現在纔有個較爲清晰的認知,那個時候只知道有aop,
根部不明白aop的作用,時至今日,任然覺得aop難以咀嚼,奈何平時不用面試要用,特此總結。
下面開始總結:
注意:我使用的是springboot2.1+maven3.6,請自行搭建基礎環境
項目github地址:https://github.com/zgq7/devloper-mine/blob/master/src/main/java/com/dev/config/aop/BaseAop.java
1:導入maven依賴
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
2:創建一個class作爲切面類,如下:
package com.dev.config.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import java.util.Collections; /** * Created by zgq7 on 2019/7/12.
* * 各通知執行順序: * 1:around-> * 2:before-> * 3:around->retrun code -> * 4:after-> * 5:afterReturning-> * 6:afterThrowing * </p> * <p> * order 執行順序: * 1:進入目的方法時:order值越小越先執行 * 2:從目的方法出去時:order值越大越先執行 * </p> */ @Aspect @Order(1) public class BaseAop { private final Logger log = LoggerFactory.getLogger(this.getClass()); /** * 寫入具體切面點 * * @apiNote execution 路徑中的 "." 如果是精確到類,則一個就行,如果是精確到包就得兩個 "." * @apiNote execution 路徑若只精確到包,就無法使用 before、after、afterReturuning、around 四個通知模塊,啓動會報錯 **/ @Pointcut("execution(public * com.dev.controller.TestController.s())") public void aspect() { } /** * 進入方法體前 **/ @Before(value = "aspect()") public void before(JoinPoint joinPoint) { log.info("before :參數類型:{}", joinPoint.getArgs()); } /** * 該切面返回數據前(在retrun之前執行) **/ @After(value = "aspect()") public void after(JoinPoint joinPoint) { log.info("aop before return :{}", joinPoint.toLongString()); } /** * 該切面返回數據後 * joinPoint.getSignature() 返回方法放回類型 及 方法路徑 **/ @AfterReturning(value = "aspect()", returning = "result") public void afterReturning(Object result) { log.info("aop after return :返回結果:{}", result); } /** * 環繞通知 * 1:before之前 * 2:afterReturning之後 * * @apiNote 1:@Around 下接的方法的參數必須爲 ProceedingJoinPoint 類型, * @apiNote 2:proceedingJoinPoint.proceed() 產生的結果即爲 @AfterReturning 中的 result,可 debug 調試 * @apiNote 3:由於@Around要提前獲取到目的方法的執行結果,且@Around提前於@AfterThrowing運行,因此異常將在@Around中被捕獲,從而導致@AfterThrowing捕獲不到異常,因此@Around與@AfterThrowing混合使用 **/ //@Around(value = "aspect()") public Object around(ProceedingJoinPoint proceedingJoinPoint) { log.info("aop arrounding :{}", proceedingJoinPoint.getSignature().getName()); try { return proceedingJoinPoint.proceed(); } catch (Throwable throwable) { log.info("aop arrounding error :{}", throwable.getMessage()); //throwable.printStackTrace(); return Collections.EMPTY_MAP; } } /** * 切面報錯 **/ @AfterThrowing(value = "aspect()", throwing = "exception") public void afterThrowing(Throwable exception) { log.error("exception occured , msg : {}", exception.getMessage()); if (exception instanceof NullPointerException) log.info("空指針異常"); } }
notice2.1:多個aspect的執行順序
1:進入目的方法時:order值越小越先執行
2:從目的方法出去時:order值越大越先執行
notice2.2:aspect 中 @befer、@after、@afterReturning、@around、@afterThrowing的執行順序
* 1:around-> * 2:before-> * 3:around->retrun code -> * 4:after-> * 5:afterReturning
notice2.2.1:各項通知也嚴格按照order的值進行傳遞一層一層的走下去
notice2.3:aspect 中@around 下屬的方法必須要有返回值,否則就是一個 “有問題” 的切面
* @apiNote 1:@Around 下接的方法的參數必須爲 ProceedingJoinPoint 類型, * @apiNote 2:proceedingJoinPoint.proceed() 產生的結果即爲 @AfterReturning 中的 result,可 debug 調試
notice2.4:aspect 中@around 不能與 @afterThrowing 混用
* @apiNote 3:由於@Around要提前獲取到目的方法的執行結果,且@Around提前於@AfterThrowing運行,因此異常將在@Around中被捕獲,從而導致@AfterThrowing捕獲不到異常,因此@Around與@AfterThrowing混合使用
notice2.5:aspect 中@PointCut中的execution類路徑或者包路徑問題
* @apiNote execution 路徑中的 "." 如果是精確到類,則一個就行,如果是精確到包就得兩個 "." * @apiNote execution 路徑若只精確到包,就無法使用 before、after、afterReturuning、around 四個通知模塊,啓動會報錯
寫的不好或總結的不好望多多見諒,有錯誤請指出,免得誤人子弟;