spring 4.0 AOP (使用AspectJ的註解方式 的aop實現)簡單例項
阿新 • • 發佈:2018-12-29
- AspectJ:Java 社群裡最完整最流行的 AOP 框架. spring aop 配合使用aspectj(AOP框架)實現我們所需的aop功能
-
在 Spring 中啟用 AspectJ 註解支援 必須在 classpath 下包含 AspectJ 類庫: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
-
AspectJ 支援 5 種類型的通知註解:
- @Before: 前置通知, 在方法執行之前執行
- @After: 後置通知, 在方法執行之後執行
- @AfterRunning: 返回通知, 在方法成功執行返回結果之後執行
- @AfterThrowing: 異常通知, 在方法丟擲異常之後
- @Around: 環繞通知, 圍繞著方法執行
- 關於Spring AOP的AspectJ切點,最重要的一點就是Spring僅支援AspectJ切點指示器(pointcut designator)的一個子集。讓我們回顧下,Spring是基於代理的,而某些切點表示式是與基於代理的AOP無關的。表4.1列出了Spring
AOP所支援的AspectJ切點指示器。
-
基於JavaConfig配置例項 如下:
-
目錄:
-
JavaConfig配置類: -
Performance介面:package aopbean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration //開啟AspectJ 自動代理模式,如果不填proxyTargetClass=true,預設為false, //即使用jdk預設代理模式,AspectJ代理模式是CGLIB代理模式 //如果目標物件實現了介面,預設情況下會採用JDK的動態代理實現AOP //如果目標物件實現了介面,可以強制使用CGLIB實現AOP (此例子我們就是強制使用cglib實現aop) //如果目標物件沒有實現了介面,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換 @EnableAspectJAutoProxy(proxyTargetClass=true) @ComponentScan public class JavaConfig { }
-
package aopbean; //目標介面 public interface Performance { public void perform(); }
dance實現類: -
package aopbean; import org.springframework.stereotype.Component; @Component public class Dance implements Performance { public void perform() { System.out.println("開始看跳舞"); } }
切面類Audience: -
測試類:package aopbean; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect//宣告切面,沒有宣告的話不會起作用 @Component public class Audience { public Audience(){ } //宣告切入點 //第一個*表示 方法 返回值(例如public int) //第二個* 表示方法的全限定名(即包名+類名) //perform表示目標方法引數括號兩個.表示任意型別引數 //方法表示式以“*”號開始,表明了我們不關心方法返回值的型別。然後,我們指定了全限定類名和方法名。對於方法引數列表, //我們使用兩個點號(..)表明切點要選擇任意的perform()方法,無論該方法的入參是什麼 //execution表示執行的時候觸發 @Pointcut("execution(* *.perform(..))") public void dancepoint(){ //該方法就是一個標識方法,為pointcut提供一個依附的地方 } @Before("dancepoint()") public void beforeDance(){ System.out.println("找座位。。。。"); } @After("dancepoint()") public void afterDance(){ System.out.println("看完回家"); } }
-
package aopbean; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class); Dance d = ac.getBean("dance",Dance.class); d.perform(); } }
輸出結果:
找座位。。。。
開始看跳舞
看完回家
- 環繞通知 round
輸出:找座位@Around("dancepoint()") public void roudDance(ProceedingJoinPoint jp) throws Throwable{ System.out.println("找座位"); jp.proceed(); System.out.println("回家"); }
開始看跳舞
回家-
可以看到,這個通知所達到的效果與之前的前置通知和後置通知是一樣的。但是,現在它們位於同一個方法中,不像之前那樣分散在四個不同的通知方法裡面。
關於這個新的通知方法,你首先注意到的可能是它接受
ProceedingJoinPoint
作為引數。這個物件是必須要有的,因為你要在通知中通過它來呼叫被通知的方法。通知方法中可以做任何的事情,當要將控制權交給被通知的方法時,它需要呼叫ProceedingJoinPoint
的proceed()
方法。需要注意的是,別忘記呼叫
proceed()
方法。如果不調這個方法的話,那麼你的通知實際上會阻塞對被通知方法的呼叫。有可能這就是你想要的效果,但更多的情況是你希望在某個點上執行被通知的方法。有意思的是,你可以不呼叫
proceed()
方法,從而阻塞對被通知方法的訪問,與之類似,你也可以在通知中對它進行多次呼叫。要這樣做的一個場景就是實現重試邏輯,也就是在被通知方法失敗後,進行重複嘗試。