Spring boot之AOP

AOP統一處理請求日誌

AOP爲Aspect Oriented Programming的縮寫,意爲:[面向切面編程]
理論就不說了,直接上代碼吧,呵呵~

註解 用途
@Aspect 註解將一個java類定義爲切面類
@Pointcut 定義一個切入點,可以是一個規則表達式,比如下例中某個package下的所有函數,也可以是一個註解等。根據需要在切入點不同位置的切入內容
@Before 在切入點開始處切入內容
@After在 切入點結尾處切入內容
@AfterReturning 在切入點return內容之後切入內容(可以用來對處理返回值做一些加工處理)
@Around在切入 點前後切入內容,並自己控制何時執行切入點自身的內容
@AfterThrowing 用來處理當切入內容部分拋出異常之後的處理邏輯

一、先建一個切面類文件吧

1.在包目錄右鍵-New-Aspect

 

建切面類1.png


2.然後會彈出框,輸出類名,下方選擇框一定要選 @Aspect,如下圖:

建切面類2.png


3.工程目錄如下:

工程目錄.png

 

二、代碼

  1. 切面類的代碼

 

@Aspect
@Component
public class TestAspect {

 @Before("execution(public * com.alun.Controller.TestController.*(..))")
    public  void onTestBefore(){
        System.out.print("-------------------------------------------調用前\n");
    }

 @After("execution(public * com.alun.Controller.TestController.*(..))")
    public  void onTestAfter(){
        System.out.print("--------------------------------------------調用後\n");
    }
}
  1. Controller的代碼

 

@RestController
public class TestController {
    @GetMapping("/firstTest")
    public  String getFirst(){
        System.out.print("-----------------我被調用了---------------\n");
        return "你好!";
    }
}
  1. 運行結果

運行結果1.png

運行結果2.png

4.打印相關信息

 

@Aspect
@Component
public class TestAspect {

    private final static Logger logger = LoggerFactory.getLogger(TestAspect.class);

    @Pointcut("execution(public * com.alun.Controller.TestController.*(..))")
    public void testLog() {
    }

    @Before("testLog()")
    public void onTestBefore(JoinPoint joinPoint) {

        logger.info("-------------------------------------------調用前\n");
        //記錄http請求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //從request中獲取http請求的url

        logger.info("url={}", request.getRequestURI());

        ///請求的方法類型
        logger.info("method={}", request.getMethod());

        //IP地址
        logger.info("ip={}", request.getRemoteAddr());

        //響應該http請求的類方法
        logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() +
                "." + joinPoint.getSignature().getName());

        //請求中的參數
        logger.info("args={}", joinPoint.getArgs());

    }

    @AfterReturning(returning = "object", pointcut = "testLog()")
    public void doAfterReturning(Object object) {
        logger.info("響應內容={}", object);
    }

    @After("testLog()")
    public void onTestAfter() {
        logger.info("--------------------------------------------調用後\n");
    }
}
  • 這裏使用了org.slf4j.Logger打印日誌,可以輸出更多信息,如時間和相關類
  • @Before和@After等括號的內容都一樣,可以提煉出來,使用@Pointcut實現
  • @Pointcut的使用:
    格式:

 

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?) 

括號中各個pattern分別表示:

  • 修飾符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern)可以爲*表示任何返回值,全路徑的類名等
  • 類路徑匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set開頭的所有方法
  • 參數匹配((param-pattern))可以指定具體的參數類型,多個參數間用“,”隔開,各個參數也可以用“”來表示匹配任意類型的參數,如(String)表示匹配一個String參數的方法;(,String) 表示匹配有兩個參數的方法,第一個參數可以是任意類型,而第二個參數是String類型;可以用(..)表示零個或多個任意參數
  • 異常類型匹配(throws-pattern?)
    其中後面跟着“?”的是可選項
    這段內容來至於這裏

運行結果:

 

運行結果

AOP切面的優先級

由於通過AOP實現,程序得到了很好的解耦,但是也會帶來一些問題,比如:我們可能會對
Web層做多個切面,校驗用戶,校驗頭信息等等,這個時候經常會碰到切面的處理順序問題。

所以,我們需要定義每個切面的優先級,我們需要@Order(i)註解來標識切面的優先級。i的值越> > 小,優先級越高。假設我們還有一個切面是CheckNameAspect用來校驗name必須爲didi,我們
爲其設置@Order(10),而上文中WebLogAspect設置爲@Order(5),所以WebLogAspect有更高
的優先級,這個時候執行順序是這樣的:

在@Before中優先執行@Order(5)的內容,再執行@Order(10)的內容
在@After和@AfterReturning中優先執行@Order(10)的內容,再執行@Order(5)的內容
所以我們可以這樣子總結:

在切入點前的操作,按order的值由小到大執行
在切入點後的操作,按order的值由大到小執行

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