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的順序是:
- 首先進入Around
- 執行joinPoint.proceed()之前,觸發Before
- 然后執行joinPoint.proceed()
- 執行joinPoint.proceed()之后,觸發After
- 最后觸發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、用一句話來形容,就是層層包圍,層層嵌套