天天看點

Spring in Action 4讀書筆記之使用标簽建立AOP定義一個aspect建立一個around advice

原文連結位址:http://tantanit.com/springinaction4-du-shu-bi-ji-zhi-shi-yong-biao-qian-chuang-jian-aop/

在之前的讀書筆記Spring in Acton 4讀書筆記之AOP原理及Spring對AOP的支援中,講到Spring對AOP的支援包含四方面:

  1. Spring基于代理的經典的AOP
  2. 使用XML配置将純POJO轉化為aspect
  3. 使用Spring的@Aspect标簽,建立aspect
  4. Spring不建立aspect,隻注入(引用)AspectJ架構的aspect

Spring in Action(Spring實戰)的第四章第三節(4.3 Creating annotated aspects)講述了其中第三種,即如何使用标簽建立aspect。本文講解其中的前面兩小節:定義aspect以及建立around advice。

AspectJ 5引進的主要特性是使用标簽建立aspect。AspectJ 5的缺點是需要學習擴充的java語言。但是AspectJ面向标簽的程式設計模式使得将一個類轉換成aspect變得很容易,隻需要在類中加一些标簽。

定義一個aspect

以下是使用标簽建立AOP的例子,這個例子在之前的文章中有提到過,觀衆在演出開始前後,以及出問題時,會自動做出一些反應:

package concert;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Audience {
  @Before("execution(** concert.Performance.perform(..))")
  public void silenceCellPhones() {
    System.out.println("Silencing cell phones");
  }
  @Before("execution(** concert.Performance.perform(..))")
  public void takeSeats() {
    System.out.println("Taking seats");
  }
  @AfterReturning("execution(** concert.Performance.perform(..))")
   public void applause() {
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("execution(** concert.Performance.perform(..))")
   public void demandRefund() {
    System.out.println("Demanding a refund");
  }
}
           

Audience類上加上@Aspect,用來表示Audience是一個aspect,而Audience被标注的方法定義了具體的行為。在表演開始前,觀衆需要就座(takeSeats()),将手機靜音(silenceCellPhones())。

表演結束後,觀衆需要鼓掌(applause()),如果表演過程中出現了異常,觀衆會要求退票(demandRefund())。AspectJ提供了五個标簽來定義advice:

  • @After,在方法正常執行結束,或者出現異常的時候,執行aspect。
  • @AfterReturning,在方法正常執行結束後,執行aspect。
  • @AfterThrowing,在方法抛出異常的時候,執行aspect。
  • @Around,在方法執行過程中,執行aspect。
  • @Before,在方法執行之前,執行aspect。

上面的例子中,所有标簽的值都是一個pointcut表達式,而且在這個例子裡,正好是一樣的(因為是作用在同一個方法上)。實際上,可以将這個pointcut定義好,然後進行引用,這樣可以避免重複編寫pointcut。

@Aspect
public class Audience {
  @Pointcut("execution(** concert.Performance.perform(..))")
  public void performance() {}

  @Before("performance()")
  public void silenceCellPhones() {
    System.out.println("Silencing cell phones");
  }
  @Before("performance()")
  public void takeSeats() {
    System.out.println("Taking seats");
  }
  @AfterReturning("performance()")
  public void applause() {
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("performance()")
  public void demandRefund() {
    System.out.println("Demanding a refund");
  }
}
           

上面的代碼,使用@Pointcut标簽對performance()方法進行标注,這樣,就可以直接使用performance()來代替pointcut表達式了。performance()隻是一個标記,是以方法體可以也必須是空的。

如果隻是定義了上面Audience這個aspect,那麼其實什麼也做不了。必須有一個配置檔案,指出它是一個aspect,并且解析這些标簽,然後建立代理,最終将Audience轉化為一個aspect。

如果是使用JavaConfig,可以在配置檔案類加上@EnableAspectJAutoProxy标簽,以實作自動代理。以下是示例:

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
  @Bean
  public Audience audience() {
    return new Audience();
  }
}
           

Spring使用AspectJ進行自動代理,僅僅是使用@AspectJ的标簽作為指引,而底層仍然是Spring自己的基于代理的aspect。是以,盡管使用了@AspectJ标簽,Spring的AOP仍然隻能作用在方法級别。如果要使用AspectJ的全部功能,就必須在運作時注入AspectJ,而不使用Spring來建立基于代理的aspect。

建立一個around advice

前面講解了before和after的用法,由于around的用法有些不同,也更有用,是以這裡單講。先看看下面的例子:

@Aspect
public class Audience {
  @Pointcut("execution(** concert.Performance.perform(..))")
  public void performance() {}

  @Around("performance()")
  public void watchPerformance(ProceedingJoinPoint jp) {
    try {
      System.out.println("Silencing cell phones");
      System.out.println("Taking seats");
      jp.proceed();
      System.out.println("CLAP CLAP CLAP!!!");
    } catch (Throwable e) {
      System.out.println("Demanding a refund");
    }
  }
}
           

使用@Around标簽标注了watchPerformance方法,監聽performance()代表的joinpoint。此時,watchPerformance的參數ProceedingJoinPoint就是指這個joinpoint。可以看到,在jp.proceed()的前後各有一些操作,甚至在抛出異常時,也有一些處理。是以,這個方法同時實作@Before、@AfterReturning和@AfterThrowing等标簽的功能,更加靈活。

需要注意的是,必須執行joinpoint的proceed()方法,否則,會導緻被監聽的方法沒有執行。

我計劃完成50到100篇關于Spring的文章,這是第十一篇,歡迎訂閱tantanit.com,第一時間擷取文章更新,本文連結位址:http://tantanit.com/springinaction4-du-shu-bi-ji-zhi-shi-yong-biao-qian-chuang-jian-aop/

歡迎掃描下方二維碼關注微信公衆号【談談IT】,第一時間擷取最新文章。

Spring in Action 4讀書筆記之使用标簽建立AOP定義一個aspect建立一個around advice