1. 程式人生 > >Sping——使用註解創建切面

Sping——使用註解創建切面

cut wire 接口 表達 turn sil wired before can

為講解例子,我們首先定義一個Performance接口:

技術分享圖片
1 package aoptest;
2 
3 public interface Performance {
4     public void perform();
5 }
View Code

再定義一個該接口的實現:

技術分享圖片
 1 package aoptest;
 2 
 3 public class PianoPerform implements Performance {
 4 
 5     @Override
 6     public void perform() {
 7         // TODO Auto-generated method stub
8 System.out.println("i am playing piano"); 9 } 10 11 }
View Code

在創建切面之前,我們先來看一下切點表達式的用法,如圖所示:

技術分享圖片

關於切點表達式的更多用法,可查看相關文檔。

接著,我們使用註解定義一個切面,Audience類會在perform方法執行前後織入指定的方法

技術分享圖片
 1 package aoptest;
 2 
 3 import org.aspectj.lang.annotation.Aspect;
 4 import org.aspectj.lang.ProceedingJoinPoint;
5 import org.aspectj.lang.annotation.*; 6 7 @Aspect 8 public class Audience { 9 10 11 @Pointcut("execution(** aoptest.Performance.perform(..))") 12 public void performance() {} 13 //performance()方法的實際內容並不重要,在這裏它是空的。 14 //其實該方法本身只是一個標識,供@Pointcut註解依附 15 //不這樣做的話,就需要在每個方法前都使用這個長點的表達式
16 17 @Before("performance()") 18 public void silenceCellPhones() { 19 System.out.println("Slience cell phones"); 20 } 21 22 @Before("performance()") 23 public void takeSeats() { 24 System.out.println("takeSeats"); 25 } 26 27 @AfterReturning("performance()") 28 public void applause() { 29 System.out.println("applause"); 30 } 31 32 @AfterThrowing("performance()") 33 public void demandRefund() { 34 System.out.println("demandRefund"); 35 } 36 }
View Code
  • @Before:通知方法會在目標方法調用之前調用
  • @AfterReturning:通知方法在目標方法成功返回後調用
  • @AfterThrowing:通知方法在目標方法拋出異常後調用
  • @Around:通知方法會將目標方法封裝起來



接著,進行測試,首先使用JavaConfig進行相關bean的配置:

技術分享圖片
 1 package aoptest;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 7 
 8 @Configuration
 9 @EnableAspectJAutoProxy   //啟用aspectJ自動代理
10 @ComponentScan
11 public class AopConfig {
12     @Bean
13     public Audience audience() {
14         return new Audience();
15     }
16     
17     @Bean 
18     Performance performance() {
19         return new PianoPerform();
20     }
21 }
View Code

然後,創建測試類:

技術分享圖片
 1 package aoptest;
 2 
 3 import org.junit.Test;
 4 import org.junit.runner.RunWith;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 8 
 9 //用於在測試開始時自動創建Spring上下文
10 @RunWith(SpringJUnit4ClassRunner.class)
11 //告訴上下文需要在AopConfig中加載配置
12 @ContextConfiguration(classes = { AopConfig.class })
13 public class PerformTest {
14     @Autowired
15     public Audience audience;
16     @Autowired
17     public Performance performance;
18         @Test
19         public void play() {
20             performance.perform();
21     }
22 }
View Code

測試結果,符合預期:

技術分享圖片

現在,我們利用@Around創建環繞通知,重新實現切面,可以達到相同的效果:

技術分享圖片
package aoptest;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class Audience {

    
    @Pointcut("execution(** aoptest.Performance.perform(..))")
    public void performance() {}
    //performance()方法的實際內容並不重要,在這裏它是空的。
    //其實該方法本身只是一個標識,供@Pointcut註解依附
    //不這樣做的話,就需要在每個方法前都使用這個長點的表達式
    
    @Around("performance()")
        //ProceedingJoinPoint這個對象是必須有的,因為需要通過它來調用被通知的方法,使用proceed()方法
    public void watchPerformance(ProceedingJoinPoint jp) {
        System.out.println("Slience cell phones");
        System.out.println("takeSeats");
        try {
            jp.proceed();
        } catch (Throwable e) {
            System.out.println("demandRefund");
        }
        System.out.println("applause");
    }
}
View Code

當然,你也可以不調用proceed()方法,從而阻塞對通知方法的訪問。

Sping——使用註解創建切面