1. 程式人生 > >spring AOP 編程--AspectJ註解方式 (4)

spring AOP 編程--AspectJ註解方式 (4)

clas 自定義 gin frame 接口 lan nts 包名 行為

1. AOP 簡介

AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對傳統 OOP(Object-Oriented Programming, 面向對象編程) 的補充.

AOP 的主要編程對象是切面(aspect), 而切面模塊化橫切關註點.

在應用 AOP 編程時, 仍然需要定義公共功能, 但可以明確的定義這個功能在哪裏, 以什麽方式應用, 並且不必修改受影響的類. 這樣一來橫切關註點就被模塊化到特殊的對象(切面)裏.

AOP 的好處:

---每個事物邏輯位於一個位置, 代碼不分散, 便於維護和升級

---業務模塊更簡潔, 只包含核心業務代碼.

2. AOP的術語和圖形表達

技術分享圖片

切面(Aspect): 橫切關註點(跨越應用程序多個模塊的功能)被模塊化的特殊對象

通知(Advice): 切面必須要完成的工作

目標(Target): 被通知的對象

代理(Proxy): 向目標對象應用通知之後創建的對象

連接點(Joinpoint):程序執行的某個特定位置:如類某個方法調用前、調用後、方法拋出異常後等。連接點由兩個信息確定:方法表示的程序執行點;相對點表示的方位。例如 ArithmethicCalculator#add() 方法執行前的連接點,執行點為 ArithmethicCalculator#add(); 方位為該方法執行前的位置

切點(pointcut):每個類都擁有多個連接點:例如 ArithmethicCalculator 的所有方法實際上都是連接點,即連接點是程序類中客觀存在的事務。AOP 通過切點定位到特定的連接點。類比:連接點相當於數據庫中的記錄,切點相當於查詢條件。切點和連接點不是一對一的關系,一個切點匹配多個連接點,切點通過 org.springframework.aop.Pointcut 接口進行描述,它使用類和方法作為連接點的查詢條件。

通知:

  前置通知(before advice):在切入點之前執行。

  後置通知(after returning advice):在切入點執行完成後,執行通知。無論是否拋出異常,都會執行。在後置通知中不能訪問方法返回的結果

  環繞通知(around advice):包圍切入點,調用方法前後完成自定義行為。

  異常通知(after throwing advice):在切入點拋出異常後,執行通知。

方式一、aspectj註解

1、需要引入一個技術分享圖片

技術分享圖片

2、ArithmeticCalculator.java

技術分享圖片
1 package com.proc;
2 
3 public interface ArithmeticCalculator {
4     int add(int i, int j);
5     int sub(int i, int j);
6     
7     int mul(int i, int j);
8     int div(int i, int j);
9 }
技術分享圖片

3、ArithmeticCalculatorImpl.java

技術分享圖片
 1 package com.proc;
 2 import org.springframework.stereotype.Component;
 3 
 4 
 5 @Component("arithmeticCalculator")
 6 public class ArithmeticCalculatorImpl implements ArithmeticCalculator{
 7     public int add(int i, int j) {
 8         int result = i + j;
 9         return result;
10     }
11 
12     public int sub(int i, int j) {
13         int result = i - j;
14         return result;
15     }
16 
17     public int mul(int i, int j) {
18         int result = i * j;
19         return result;
20     }
21 
22     public int div(int i, int j) {
23         int result = i / j;
24         return result;
25     }
26 }
技術分享圖片

4、LoggingAspect.java

技術分享圖片
 1 package com.proc;
 2 
 3 import org.aspectj.lang.JoinPoint;
 4 import org.aspectj.lang.annotation.Aspect;
 5 import org.aspectj.lang.annotation.Before;
 6 import org.springframework.stereotype.Component;
 7 
 8 @Aspect
 9 @Component
10 public class LoggingAspect {
11 
12     @Before("execution(* *.*(int,int))")
13     public void beforeMethod(JoinPoint point){
14         System.out.println("正在執行方法: "+point.getSignature().getName());
15     }
16 }
技術分享圖片

  這是一個日誌切面類,該類首先是一個IoC中的bean,通過@Component將bean交個容器管理,然後@Aspect聲明這是一個切面。

  @Before是通知時機,表示在調用方法之前通知。 裏面字符串格式為execution (訪問修飾符 返回類型 包名.類名.方法名(參數類型...))。

  beforeMethod是定一個的一個切面執行的方法,方法名可以任意指定。可以不帶參數,也可以指定一個JoinPoint連接點的參數。

配置

1 <context:component-scan base-package="com.proc" />
2 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  aop:aspectj-autoproxy:使得@Aspect註解生效

測試代碼:

技術分享圖片
1 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
2 ArithmeticCalculator calc=(ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
3 System.out.println(calc.add(3, 5));
4 System.out.println(calc.sub(3, 5)); 
5 System.out.println(calc.mul(6, 2)); 
6 System.out.println(calc.div(6, 2)); 
技術分享圖片

輸出結果

技術分享圖片
正在執行方法add
8
正在執行方法sub
-2
正在執行方法mul
12
正在執行方法div
3
技術分享圖片

上面方法是用的前置通知。下面我們講解一下後置通知、返回通知、異常通知和環繞通知

☆後置通知

  後置通知無論方法是否拋出異常,都會執行。在後置通知中不能訪問返回結果,因為可能會出現異常,就沒有返回值

1 @After("execution(* *.*(int,int))")
2 public void afterMethod(JoinPoint point){
3     System.out.println("方法執行結束: "+point.getSignature().getName());
4 }

☆返回通知

  當方法有異常時,不會執行返回通知,只有在方法正常執行結束才能夠執行返回通知。在結果通知中用參數returning來指定接收返回結果對象的名稱,直接傳遞給下面方法中對應的參數

1 @AfterReturning(value="execution(* *.*(int,int))",returning="retVal")
2 public void afterReturningMethod(JoinPoint point,Object retVal){
3     System.out.println("方法: "+point.getSignature().getName()+"執行結果為:"+retVal);
4 }

☆異常通知

  當方法有異常時,才會執行返回異常通知

1 @AfterThrowing(value="execution(* *.*(int,int))",throwing="ex")
2 public void afterThrowingMethod(JoinPoint point,Exception ex){
3     System.out.println("執行方法: "+point.getSignature().getName()+"出現了異常:"+ex.getMessage());
4 }

【註意】:在指定異常類型時,只能捕獲到該類型或子類型的異常。比如指定NullPointerException異常,就只能捕獲空指針異常,所以,我們可以指定為異常的父類型。

☆環繞通知

  環繞通知是一個比較強大,但相對復雜一點的通知,我們通常不使用

技術分享圖片
 1 @Around("execution(* *.*(int,int))")
 2 public Object aroundMethod(ProceedingJoinPoint point){
 3     
 4     System.out.println("環繞通知: "+point.getSignature().getName());
 5     Object result=null;
 6     //這裏相當於前置通知
 7     try {
 8         //執行方法
 9         result= point.proceed();
10         //這裏相當於結果通知
11     } catch (Throwable e) {
12         //這裏相當於異常通知
13         e.printStackTrace();
14         
15     }
16     //這裏相當於後置通知
17     System.out.println("環繞通知: "+point.getSignature().getName());
18     return result;
19 }
技術分享圖片

【註意】:環繞通知要求有一個返回值point.proceed()執行方法,並提供一個返回值

spring AOP 編程--AspectJ註解方式 (4)