Spring(十五)Spring AOP 初窺

AOP: 面向切面編程(Aspect Oriented Programming),和Java結構中的OOP是截然不同兩種的邏輯,可以理解爲是對OOP的一種補充,對程序結構的另一種思考。
在OOP的一等公民是類(Class),而在AOP中則是切面(Aspect),AOP典型應用就是事務管理器。
其實在Spring IoC 容器並不依賴於AOP,所以你可以在IoC中不使用AOP,但是在 Spring 使用AOP 提供了非常方面的支持。
本文將簡單介紹AOP用法,包括各個名詞定義與舉例。

本文大部分知識點,來源於Spring 官方文檔:https://docs.spring.io/spring/docs/2.5.x/reference/aop.html

例子

下面是在Spring 中,定義一個切面:

@Aspect
public class WorldAop implements Ordered {
    @Pointcut("execution(* com.anla.springaop.service.*.*(..))")
    private void returnPointcut() {
    }

    @Before("returnPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        String apiName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        System.out.println("========== 調用方法WorldAop:{} start ==========, " + apiName);
        for (Object arg : joinPoint.getArgs()) {
            System.out.println("arg:," + arg);
        }
        System.out.println("========== 調用方法WorldAop:{} end ==========, " + apiName);
    }

    @Around("returnPointcut()")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("pjp is :" + pjp);
        return pjp.proceed();
    }

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

@Aspect

@Aspect 註解,表明這個類是個切面。
例如:

@Aspect
public class NotVeryUsefulAspect {

}

@Pointcut

@Pointcut 定義一個切入點,可以理解爲正則表達式,即類方法方法執行點的表達式。

實際上,AOP切點支持在任意位置切入,但是Spring AOP 只支持部分 PointCut表達式:

  • execution 用於匹配方法的切入點
  • within 限制切點爲某一些特定的類型。即對Spring 切入點的所有方法
  • this 限定當前執行的方法的 bean實例 是某一種類型
  • target 限制執行放的類型是某一種類型,和上一種來說是對比方法不同,使用this和使用target。
  • args 限制執行的方法,參數是怎樣的
  • @target: 限制切入點,這個類具有某一種類型的註解
  • @args: 限制方法的參數,是使用什麼樣的註解
  • @within:
  • @annotation: 限制切入點,方法有 這個註解時候會被攔截

執行階段切面

這裏包括這幾種註解:@Before, @AfterReturning, @AfterThrowing , @Around等幾種。
分別是代表 方法執行前後的邏輯(@Before, @AfterReturning),以及 報錯後的邏輯@AfterThrowing
方法執行前後的邏輯,包括前和後 @Around
例如 下面 @Around 例子:

@Aspect
public class ConcurrentOperationExecutor implements Ordered {
   private static final int DEFAULT_MAX_RETRIES = 2;
   private int maxRetries = DEFAULT_MAX_RETRIES;
   private int order = 1;
   public void setMaxRetries(int maxRetries) {
      this.maxRetries = maxRetries;
   }
   public int getOrder() {
      return this.order;
   }
   
   public void setOrder(int order) {
      this.order = order;
   }
   // Around 類型切面
   @Around("com.xyz.myapp.SystemArchitecture.businessService()")
   public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { 
      int numAttempts = 0;
      PessimisticLockingFailureException lockFailureException;
      do {
         numAttempts++;
         try { 
            return pjp.proceed();
         }
         catch(PessimisticLockingFailureException ex) {
            lockFailureException = ex;
         }
      }
      while(numAttempts <= this.maxRetries);
      throw lockFailureException;
   }

}

如果切面需要狀態?

如果切面不是單例的,需要狀態怎麼做?
例如熔斷降級,需要監控每一個方法,他們有不同狀態,Spring AOP提供了一種基於類似於原型模式方法:

@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {

  private int someState;
	
  @Before(com.xyz.myapp.SystemArchitecture.businessService())
  public void recordServiceUsage() {
    // ...
  }
  	
}

即使用 @Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())") 這種方式去聲明一個切面,那麼每一個切入點都會有一個切面了。

參考:

  1. https://docs.spring.io/spring/docs/2.5.x/reference/aop.html
  2. 一些自定義 的 AOP

覺得博主寫的有用,不妨關注博主公衆號: 六點A君。
哈哈哈,一起研究Spring:
在這裏插入圖片描述

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