java 切面表达式_Spring(十九):Spring AOP(三):切面的优先级、重复使用切入点表达式...

背景:

1)指定切面优先级示例:有的时候需要对一个方法指定多个切面,而这多个切面有时又需要按照不同顺序执行,因此,切面执行优先级别指定功能就变得很实用。

2)重复使用切入点表达式:上一篇文章中,定义前置、后置、返回、异常通知的切入点表达式时,都使用了同一个;而且本章节新加入的验证切面ValidateAspect类,也使用同一个切入点表达式,怎么让他们重用呢?

指定切面优先级示例:

比如在算术计算器执行计算之前进行数据验证,验证完事之后才让执行日志输出。

添加验证切面类:

packagecom.dx.spring.beans.aop;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.springframework.stereotype.Component;

@Component

@Aspectpublic classValidateAspect {

@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public voidbeforeMethod() {

System.out.println("validate...");

}

}

除了验证切面,还包含日志切面:

packagecom.dx.spring.beans.aop;importjava.util.List;importjava.util.Arrays;importorg.aspectj.lang.JoinPoint;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.After;importorg.aspectj.lang.annotation.AfterReturning;importorg.aspectj.lang.annotation.AfterThrowing;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.annotation.Before;importorg.springframework.stereotype.Component;//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。

@Aspect

@Componentpublic classLoggingAspect {//声明该方法为一个前置通知:在目标方法开始之前执行

@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int, int))")public voidbeforeMethod(JoinPoint joinpoint) {

String methodName=joinpoint.getSignature().getName();

List args =Arrays.asList(joinpoint.getArgs());

System.out.println("before method " + methodName + " with " +args);

}//声明该方法为一个后置通知:在目标方法结束之后执行(无论方法是否抛出异常)。//但是因为当方法抛出异常时,不能返回值为null,因此这里无法获取到异常值。

@After(value = "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))")public voidafterMethod(JoinPoint joinpoint) {

String methodName=joinpoint.getSignature().getName();

List args =Arrays.asList(joinpoint.getArgs());

System.out.println("after method " +methodName);

}/*** 声明该方法为一个返回通知:在目标方法返回结果时后执行(当方法抛出异常时,无法执行)。 但是因为当方法抛出异常时,类似代码 {@code* try

* {

* // before 前置通知

* // do action method

* // after returning 返回通知,可以访问到方法的返回值

* } catch(Exception e){ e.printStackTrace(); // after throwing

* 异常通知,可以访问到方法出现的异常 } // after 后置通知,因为方法可以抛出异常,所以访问不到方法的返回值 }*/@AfterReturning(value= "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", returning = "result")public voidafterReturningMethod(JoinPoint joinpoint, Object result) {

String methodName=joinpoint.getSignature().getName();

List args =Arrays.asList(joinpoint.getArgs());

System.out.println("after method " + methodName + " with returning " + (result == null ? "NULL": result.toString()));

}/*** 定义一个异常通知函数: 只有在方法跑吹异常时,该方法才会执行,而且可以接受异常对象。*/@AfterThrowing(value= "execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(int,int))", throwing = "ex")public voidafterThrowingMethod(JoinPoint joinpoint, Exception ex) {

String methodName=joinpoint.getSignature().getName();

List 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 args = Arrays.asList(pJoinPoint.getArgs());//

//Object result = null;//try {// //前置通知//System.out.println("before method " + methodName + " with " + args);// //执行目标方法//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;//}

}

默认打印结果:

42ab5025d9e0b39c0ef76c93f9c61203.png

按照实际业务需求来讲,更希望是先执行验证切面,才执行日志切面,那么,可以通过设置切面优先级别来设置:

修改ValidateAspect.java添加注解@Order(1)

@Order(value=1)

@Component

@Aspectpublic classValidateAspect {

@Before("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public voidbeforeMethod() {

System.out.println("validate...");

}

}

修改LoggingAspect.java添加注解@Order(2)

@Order(value=2)

@Aspect

@Componentpublic classLoggingAspect {//代码

}

此时执行结果为:

1d35d319d4ba74ea164b6ad6282fa8f3.png

重使用切入点表达式:

上一篇文章中,定义前置、后置、返回、异常通知的切入点表达式时,都使用了同一个;而且本章节新加入的验证切面ValidateAspect类,也使用同一个切入点表达式,怎么让他们重用呢?

第一步:修改LoggingAspect切面类,添加@Pointcut注解的方法declareAspectJoinPointExpression():

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。

@Order(value=2)

@Aspect

@Componentpublic classLoggingAspect {

@Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public voiddeclareAspectJoinPointExpression(){

}//...

}

第二步:修改LoggingAspect切面类,把前置、后置、返回、异常、环绕通知方法的切入点表达式替换为“declareAspectJoinPointExpression()”

以前置通知方法为例:

//把这个类声明为一个切面:需要把该类放入到IOC容器中、再声明为一个切面。

@Order(value=2)

@Aspect

@Componentpublic classLoggingAspect {

@Pointcut("execution(public int com.dx.spring.beans.aop.IArithmeticCalculator.*(..))")public voiddeclareAspectJoinPointExpression(){

}//声明该方法为一个前置通知:在目标方法开始之前执行

@Before("declareAspectJoinPointExpression()")public voidbeforeMethod(JoinPoint joinpoint) {

String methodName=joinpoint.getSignature().getName();

List args =Arrays.asList(joinpoint.getArgs());

System.out.println("before method " + methodName + " with " +args);

}//...

}

第三步:修改验证切面类ValidateAspect.java:

@Order(value=1)

@Component

@Aspectpublic classValidateAspect {

@Before("com.dx.spring.beans.aop.LoggingAspect.declareAspectJoinPointExpression()")public voidbeforeMethod() {

System.out.println("validate...");

}

}

备注:如果在同一个包下,可以不指定包的路径。

第四步:验证

1518bfa3168fa94d53cb9dfa6b804a62.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值