Spring AOP--返回通知,異常通知和環繞通知


在上篇文章中學習了Spring AOP,並學習了前置通知和后置通知。地址為:http://www.cnblogs.com/dreamfree/p/4095858.html

在本文中,將繼續上篇的學習,繼續了解返回通知、異常通知和環繞通知。具體的含義詳見代碼注釋

 1 package com.yl.spring.aop;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.aspectj.lang.JoinPoint;
 6 import org.aspectj.lang.ProceedingJoinPoint;
 7 import org.aspectj.lang.annotation.After;
 8 import org.aspectj.lang.annotation.AfterReturning;
 9 import org.aspectj.lang.annotation.AfterThrowing;
10 import org.aspectj.lang.annotation.Around;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.springframework.stereotype.Component;
14 
15 @Component
16 @Aspect
17 public class LoggingAspect {
18     
19     /**
20      * 在com.yl.spring.aop.ArithmeticCalculator接口的每一個實現類的每一個方法開始之前執行一段代碼
21      */
22     @Before("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
23     public void beforeMethod(JoinPoint joinPoint) {
24         String methodName = joinPoint.getSignature().getName();
25         Object[] args = joinPoint.getArgs();
26         System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
27     }
28     
29     /**
30      * 在com.yl.spring.aop.ArithmeticCalculator接口的每一個實現類的每一個方法執行之后執行一段代碼
31      * 無論該方法是否出現異常
32      */
33     @After("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
34     public void afterMethod(JoinPoint joinPoint) {
35         String methodName = joinPoint.getSignature().getName();
36         Object[] args = joinPoint.getArgs();
37         System.out.println("The method " + methodName + " ends with " + Arrays.asList(args));
38     }
39     
40     /**
41      * 方法正常結束后執行的代碼
42      * 返回通知是可以訪問到方法的返回值的
43      */
44     @AfterReturning(value="execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))", returning="result")
45     public void afterReturning(JoinPoint joinPoint, Object result) {
46         String methodName = joinPoint.getSignature().getName();
47         System.out.println("The method " + methodName + " return with " + result);
48     }
49     
50     /**
51      * 在方法出現異常時會執行的代碼
52      * 可以訪問到異常對象,可以指定在出現特定異常時在執行通知代碼
53      */
54     @AfterThrowing(value="execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))", throwing="ex")
55     public void afterThrowing(JoinPoint joinPoint, Exception ex) {
56         String methodName = joinPoint.getSignature().getName();
57         System.out.println("The method " + methodName + " occurs exception: " + ex);
58     }
59     
60     /**
61      * 環繞通知需要攜帶ProceedingJoinPoint類型的參數
62      * 環繞通知類似於動態代理的全過程:ProceedingJoinPoint類型的參數可以決定是否執行目標方法。
63      * 而且環繞通知必須有返回值,返回值即為目標方法的返回值
64      */
65     @Around("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
66     public Object aroundMethod(ProceedingJoinPoint pjd) {
67         Object result = null;
68         String methodName = pjd.getSignature().getName();
69         //執行目標方法
70         try {
71             //前置通知
72             System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
73             result = pjd.proceed();
74             //返回通知
75             System.out.println("The method " + methodName + " ends with " + Arrays.asList(pjd.getArgs()));
76         } catch (Throwable e) {
77             //異常通知
78             System.out.println("The method " + methodName + " occurs expection : " + e);
79             throw new RuntimeException(e);
80         }
81         //后置通知
82         System.out.println("The method " + methodName + " ends");
83         return result;
84     }
85     
86 }

 

切面的優先級  

  為項目增加一個新的切面類,負責驗證功能,則需要指定切面執行的順序。即切面的優先級。具體方法是給切面類增加@Order注解,並指定具體的數字,值越小優先級越高

 1 package com.yl.spring.aop;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.aspectj.lang.JoinPoint;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.springframework.core.annotation.Order;
 9 import org.springframework.stereotype.Component;
10 
11 /**
12  * 可以使用@Order注解指定切面的優先級,值越小優先級越高
13  * @author yul
14  *
15  */
16 @Order(2)
17 @Component
18 @Aspect
19 public class ValidationAspect {
20     
21     @Before("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
22     public void vlidateArgs(JoinPoint joinPoint) {
23         System.out.println("validate: " + Arrays.asList(joinPoint.getArgs()));
24     }
25 }

 切點表達式的重用:

  在LoggingAspect類中,切點的表達式可以先定義,在使用。

 1 package com.yl.spring.aop;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.aspectj.lang.JoinPoint;
 6 import org.aspectj.lang.ProceedingJoinPoint;
 7 import org.aspectj.lang.annotation.After;
 8 import org.aspectj.lang.annotation.AfterReturning;
 9 import org.aspectj.lang.annotation.AfterThrowing;
10 import org.aspectj.lang.annotation.Around;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.aspectj.lang.annotation.Pointcut;
14 import org.springframework.core.annotation.Order;
15 import org.springframework.stereotype.Component;
16 @Order(1)
17 @Component
18 @Aspect
19 public class LoggingAspect {
20     
21     /**
22      * 定義一個方法,用於聲明切入點表達式。一般的,該方法中再不需要添加其他的代碼
23      * 使用@Pointcut 來聲明切入點表達式
24      * 后面的其他通知直接使用方法名直接引用方法名即可
25      */
26     @Pointcut("execution(public int com.yl.spring.aop.ArithmeticCalculator.*(..))")
27     public void declareJoinPointExpression() {
28         
29     }
30     
31     /**
32      * 在com.yl.spring.aop.ArithmeticCalculator接口的每一個實現類的每一個方法開始之前執行一段代碼
33      */
34     @Before("declareJoinPointExpression()")
35     public void beforeMethod(JoinPoint joinPoint) {
36         String methodName = joinPoint.getSignature().getName();
37         Object[] args = joinPoint.getArgs();
38         System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
39     }
40     
41     /**
42      * 在com.yl.spring.aop.ArithmeticCalculator接口的每一個實現類的每一個方法執行之后執行一段代碼
43      * 無論該方法是否出現異常
44      */
45     @After("declareJoinPointExpression()")
46     public void afterMethod(JoinPoint joinPoint) {
47         String methodName = joinPoint.getSignature().getName();
48         Object[] args = joinPoint.getArgs();
49         System.out.println("The method " + methodName + " ends with " + Arrays.asList(args));
50     }
51     
52     /**
53      * 方法正常結束后執行的代碼
54      * 返回通知是可以訪問到方法的返回值的
55      */
56     @AfterReturning(value="declareJoinPointExpression()", returning="result")
57     public void afterReturning(JoinPoint joinPoint, Object result) {
58         String methodName = joinPoint.getSignature().getName();
59         System.out.println("The method " + methodName + " return with " + result);
60     }
61     
62     /**
63      * 在方法出現異常時會執行的代碼
64      * 可以訪問到異常對象,可以指定在出現特定異常時在執行通知代碼
65      */
66     @AfterThrowing(value="declareJoinPointExpression()", throwing="ex")
67     public void afterThrowing(JoinPoint joinPoint, Exception ex) {
68         String methodName = joinPoint.getSignature().getName();
69         System.out.println("The method " + methodName + " occurs exception: " + ex);
70     }
71     
72     /**
73      * 環繞通知需要攜帶ProceedingJoinPoint類型的參數
74      * 環繞通知類似於動態代理的全過程:ProceedingJoinPoint類型的參數可以決定是否執行目標方法。
75      * 而且環繞通知必須有返回值,返回值即為目標方法的返回值
76      */
77     @Around("declareJoinPointExpression()")
78     public Object aroundMethod(ProceedingJoinPoint pjd) {
79         Object result = null;
80         String methodName = pjd.getSignature().getName();
81         //執行目標方法
82         try {
83             //前置通知
84             System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
85             result = pjd.proceed();
86             //返回通知
87             System.out.println("The method " + methodName + " ends with " + Arrays.asList(pjd.getArgs()));
88         } catch (Throwable e) {
89             //異常通知
90             System.out.println("The method " + methodName + " occurs expection : " + e);
91             throw new RuntimeException(e);
92         }
93         //后置通知
94         System.out.println("The method " + methodName + " ends");
95         return result;
96     }
97     
98 }

當處於不同的類,甚至不同的包時,可以使用包名.類名.方法名    

具體代碼如下:

 1 package com.yl.spring.aop;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.aspectj.lang.JoinPoint;
 6 import org.aspectj.lang.annotation.Aspect;
 7 import org.aspectj.lang.annotation.Before;
 8 import org.springframework.core.annotation.Order;
 9 import org.springframework.stereotype.Component;
10 
11 /**
12  * 可以使用@Order注解指定切面的優先級,值越小優先級越高
13  * @author yul
14  *
15  */
16 @Order(2)
17 @Component
18 @Aspect
19 public class ValidationAspect {
20     
21     @Before("com.yl.spring.aop.LoggingAspect.declareJoinPointExpression()")
22     public void vlidateArgs(JoinPoint joinPoint) {
23         System.out.println("validate: " + Arrays.asList(joinPoint.getArgs()));
24     }
25 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM