在上篇文章中學習了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 }