總結一下springboot2.x中的AOP機制(附帶demo)

寄語:剛開始學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 四個通知模塊,啓動會報錯










寫的不好或總結的不好望多多見諒,有錯誤請指出,免得誤人子弟;



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章