javascript
Spring(十九):Spring AOP(三):切面的优先级、重复使用切入点表达式
背景:
1)指定切面優(yōu)先級示例:有的時候需要對一個方法指定多個切面,而這多個切面有時又需要按照不同順序執(zhí)行,因此,切面執(zhí)行優(yōu)先級別指定功能就變得很實用。
2)重復使用切入點表達式:上一篇文章中,定義前置、后置、返回、異常通知的切入點表達式時,都使用了同一個;而且本章節(jié)新加入的驗證切面ValidateAspect類,也使用同一個切入點表達式,怎么讓他們重用呢?
指定切面優(yōu)先級示例:
比如在算術計算器執(zhí)行計算之前進行數(shù)據(jù)驗證,驗證完事之后才讓執(zhí)行日志輸出。
新建spring aop項目參考:《Spring(十八):Spring AOP(二):通知(前置、后置、返回、異常、環(huán)繞)》
添加驗證切面類:
package com.dx.spring.beans.aop;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;@Component @Aspect public class ValidateAspect { @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public void beforeMethod() {System.out.println("validate...");} }除了驗證切面,還包含日志切面:
package com.dx.spring.beans.aop;import java.util.List; import java.util.Arrays;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component;//把這個類聲明為一個切面:需要把該類放入到IOC容器中、再聲明為一個切面。 @Aspect @Component public class LoggingAspect {// 聲明該方法為一個前置通知:在目標方法開始之前執(zhí)行@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public void beforeMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("before method " + methodName + " with " + args);}// 聲明該方法為一個后置通知:在目標方法結束之后執(zhí)行(無論方法是否拋出異常)。// 但是因為當方法拋出異常時,不能返回值為null,因此這里無法獲取到異常值。@After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")public void afterMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName);}/*** 聲明該方法為一個返回通知:在目標方法返回結果時后執(zhí)行(當方法拋出異常時,無法執(zhí)行)。 但是因為當方法拋出異常時,類似代碼 {@code* try <br/>* { <br/>* // before 前置通知 <br/>* // do action method <br/>* // after returning 返回通知,可以訪問到方法的返回值 <br/>* } catch(Exception e){ e.printStackTrace(); // after throwing* 異常通知,可以訪問到方法出現(xiàn)的異常 } // after 后置通知,因為方法可以拋出異常,所以訪問不到方法的返回值 }*/@AfterReturning(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")public void afterReturningMethod(JoinPoint joinpoint, Object result) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + " with returning " + (result == null ? "NULL" : result.toString()));}/*** 定義一個異常通知函數(shù): 只有在方法跑吹異常時,該方法才會執(zhí)行,而且可以接受異常對象。*/@AfterThrowing(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinpoint, Exception ex) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("after method " + methodName + " occurs exception: " + (ex == null ? "NULL" : ex.getMessage()));}// @Around(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))") // public Object aroundMethod(ProceedingJoinPoint pJoinPoint) throws Exception { // String methodName = pJoinPoint.getSignature().getName(); // List<Object> args = Arrays.asList(pJoinPoint.getArgs()); // // Object result = null; // try { // // 前置通知 // System.out.println("before method " + methodName + " with " + args); // // 執(zhí)行目標方法 // result = pJoinPoint.proceed(); // // 返回通知 // System.out.println("after method " + methodName + " returning " + result); // } catch (Throwable ex) { // // 異常通知 // System.out.println("after method " + methodName + " occurs exception: " + ex.getMessage()); // throw new Exception(ex); // } // // 后置通知 // System.out.println("after method " + methodName); // return result; // } }默認打印結果:
按照實際業(yè)務需求來講,更希望是先執(zhí)行驗證切面,才執(zhí)行日志切面,那么,可以通過設置切面優(yōu)先級別來設置:
修改ValidateAspect.java添加注解@Order(1)
@Order(value=1) @Component @Aspect public class ValidateAspect { @Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public void beforeMethod() {System.out.println("validate...");} }修改LoggingAspect.java添加注解@Order(2)
@Order(value=2) @Aspect @Component public class LoggingAspect {//代碼 }此時執(zhí)行結果為:
重使用切入點表達式:
上一篇文章中,定義前置、后置、返回、異常通知的切入點表達式時,都使用了同一個;而且本章節(jié)新加入的驗證切面ValidateAspect類,也使用同一個切入點表達式,怎么讓他們重用呢?
第一步:修改LoggingAspect切面類,添加@Pointcut注解的方法declareAspectJoinPointExpression():
//把這個類聲明為一個切面:需要把該類放入到IOC容器中、再聲明為一個切面。 @Order(value=2) @Aspect @Component public class LoggingAspect {@Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public void declareAspectJoinPointExpression(){}//... }第二步:修改LoggingAspect切面類,把前置、后置、返回、異常、環(huán)繞通知方法的切入點表達式替換為“declareAspectJoinPointExpression()”
以前置通知方法為例:
//把這個類聲明為一個切面:需要把該類放入到IOC容器中、再聲明為一個切面。 @Order(value=2) @Aspect @Component public class LoggingAspect {@Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public void declareAspectJoinPointExpression(){}// 聲明該方法為一個前置通知:在目標方法開始之前執(zhí)行@Before("declareAspectJoinPointExpression()")public void beforeMethod(JoinPoint joinpoint) {String methodName = joinpoint.getSignature().getName();List<Object> args = Arrays.asList(joinpoint.getArgs());System.out.println("before method " + methodName + " with " + args);}//... }第三步:修改驗證切面類ValidateAspect.java:
@Order(value=1) @Component @Aspect public class ValidateAspect { @Before("com.dx.spring.beans.aop.LoggingAspect.declareAspectJoinPointExpression()")public void beforeMethod() {System.out.println("validate...");} }備注:如果在同一個包下,可以不指定包的路徑。
第四步:驗證
?
轉載于:https://www.cnblogs.com/yy3b2007com/p/9131005.html
總結
以上是生活随笔為你收集整理的Spring(十九):Spring AOP(三):切面的优先级、重复使用切入点表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pat1100. Mars Number
- 下一篇: 图论测试题(一)第一题:longest