Sping——使用註解創建切面
阿新 • • 發佈:2018-12-22
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 stubView Code8 System.out.println("i am playing piano"); 9 } 10 11 }
在創建切面之前,我們先來看一下切點表達式的用法,如圖所示:
關於切點表達式的更多用法,可查看相關文檔。
接著,我們使用註解定義一個切面,Audience類會在perform方法執行前後織入指定的方法:
1 package aoptest; 2 3 import org.aspectj.lang.annotation.Aspect; 4 import org.aspectj.lang.ProceedingJoinPoint;View Code5 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 }
- @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——使用註解創建切面