Spring AOP講解(Pointcut、Before、Around、AfterReturning、After)


AOP依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

@Pointcut

定義切入點,有以下2種方式:

方式一:設置為注解@LogFilter1標記的方法,有標記的方法觸發該AOP,沒有標記就沒有。

@Aspect
@Component
public class LogFilter1Aspect {
	@Pointcut(value = "@annotation(com.train.aop.annotation.LogFilter1)")
	public void pointCut(){
	
	}
}

附上LogFilter1代碼:

@Target(ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface LogFilter1 {
}

對應的Controller方法如下,手動添加@LogFilter1注解:

@RestController
public class AopController {

	@RequestMapping("/aop")
	@LogFilter1
	public String aop(){
	    System.out.println("這是執行方法");
	    return "success";
	}
}

方式二:采用表達式批量添加切入點,如下方法,表示AopController下的所有public方法都添加LogFilter1切面

@Pointcut(value = "execution(public * com.train.aop.controller.AopController.*(..))")
public void pointCut(){

}

@Around

環繞通知,可以說是使用最頻繁的方式,會將整個方法包圍起來

@Around(value = "pointCut()")
public Object round(ProceedingJoinPoint joinPoint){
    System.out.println("1、Round begin");
    Object obj = null;
    try {
        obj = joinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println("1、Round end");
    return obj;
}

@Before

前置方法,在目標方法執行前觸發

@Before(value = "pointCut()")
public void before(){
    System.out.println("1、Before");
}

@After

后置方法,與@Before相反,在目標方法執行完畢后執行

@After(value = "pointCut()")
public void after(){
    System.out.println("1、After");
}

@AfterReturning

后置通知,在將返回值返回時執行

@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(Object result){
    System.out.println("1、AfterReturning");
}

測試

接下來執行最開始聲明的AopController,輸出如下:

1、Round begin
1、Before
這是執行方法
1、Round end
1、After
1、AfterReturning

由此可見,AOP的順序是:

  1. 首先進入Around
  2. 執行joinPoint.proceed()之前,觸發Before
  3. 然后執行joinPoint.proceed()
  4. 執行joinPoint.proceed()之后,觸發After
  5. 最后觸發AfterReturning

多個AOP執行順序

當創建了多個自定義注解,並標記到同一個方法上,可以通過設置Order來指定執行順序。
這邊創建一個LogFilter2、LogFilter2Aspect,代碼跟上面的例子一樣,把“1”改成“2”就行

方式一:添加注解@Order

@Aspect
@Component
@Order(1)
public class LogFilter1Aspect {
}
@Aspect
@Component
@Order(2)
public class LogFilter2Aspect {
}

方式二:實現Ordered接口

@Aspect
@Component
public class LogFilter1Aspect implements Ordered {

    @Override
    public int getOrder() {
        return 1;
    }
}
@Aspect
@Component
public class LogFilter2Aspect implements Ordered {

    @Override
    public int getOrder() {
        return 2;
    }
}

在Controller代碼把2個注解都加上:

@RequestMapping("/aop")
@LogFilter1
@LogFilter2
public String aop(){
    System.out.println("這是執行方法");
    return "success";
}

執行結果如下:

1、Round begin
1、Before
2、Round begin
2、Before
這是執行方法
2、Round end
2、After
2、AfterReturning
1、Round end
1、After
1、AfterReturning

由此可見,Order越小的越優先執行,但是,After方法反而越后面執行,用一張圖表示
在這里插入圖片描述

1、外層的是LogFilter1,因為Order設置為1,最小優先進入
2、里層的是LogFilter2,因為Order設置為2,所以在LogFilter1后面執行
3、出來的時候,先穿過的是LogFilter2,然后才穿過LogFilter1,這也就是為什么LogFilter2的After方法會先執行
4、用一句話來形容,就是層層包圍,層層嵌套


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM