当前位置: 首页 > news >正文

(36)通知与切面

通知类型

通知类型包括:

  • 前置通知:@Before 目标方法执行之前的通知
  • 后置通知:@AfterReturning 目标方法执行之后的通知
  • 环绕通知:@Around 目标方法之前添加通知,同时目标方法执行之后添加通知。
  • 异常通知:@AfterThrowing 发生异常之后执行的通知
  • 最终通知:@After 放在finally语句块中的通知

接下来,编写程序来测试这几个通知的执行顺序:

packagecom.powernode.spring6.service;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.stereotype.Component;// 切面类@Component@AspectpublicclassMyAspect{@Around("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidaroundAdvice(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println("环绕通知开始");// 执行目标方法。proceedingJoinPoint.proceed();System.out.println("环绕通知结束");}@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidbeforeAdvice(){System.out.println("前置通知");}@AfterReturning("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterReturningAdvice(){System.out.println("后置通知");}@AfterThrowing("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterThrowingAdvice(){System.out.println("异常通知");}@After("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterAdvice(){System.out.println("最终通知");}}
packagecom.powernode.spring6.service;importorg.springframework.stereotype.Component;// 目标类@ComponentpublicclassOrderService{// 目标方法publicvoidgenerate(){System.out.println("订单已生成!");}}
packagecom.powernode.spring6.test;importcom.powernode.spring6.service.OrderService;importorg.junit.Test;importorg.springframework.context.ApplicationContext;importorg.springframework.context.support.ClassPathXmlApplicationContext;publicclassAOPTest{@TestpublicvoidtestAOP(){ApplicationContextapplicationContext=newClassPathXmlApplicationContext("spring-aspectj-aop-annotation.xml");OrderServiceorderService=applicationContext.getBean("orderService",OrderService.class);orderService.generate();}}

执行结果:

通过上面的执行结果就可以判断他们的执行顺序了,这里不再赘述。
结果中没有异常通知,这是因为目标程序执行过程中没有发生异常。我们尝试让目标方法发生异常:

packagecom.powernode.spring6.service;importorg.springframework.stereotype.Component;// 目标类@ComponentpublicclassOrderService{// 目标方法publicvoidgenerate(){System.out.println("订单已生成!");if(1==1){thrownewRuntimeException("模拟异常发生");}}}

再次执行测试程序,结果如下:

通过测试得知,当发生异常之后,最终通知也会执行,因为最终通知@After会出现在finally语句块中。
出现异常之后,后置通知环绕通知的结束部分不会执行。

切面的先后顺序

我们知道,业务流程当中不一定只有一个切面,可能有的切面控制事务,有的记录日志,有的进行安全控制,如果多个切面的话,顺序如何控制:可以使用@Order注解来标识切面类,为@Order注解的value指定一个整数型的数字,数字越小,优先级越高
再定义一个切面类,如下:

packagecom.powernode.spring6.service;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;@Aspect@Component@Order(1)//设置优先级publicclassYourAspect{@Around("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidaroundAdvice(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println("YourAspect环绕通知开始");// 执行目标方法。proceedingJoinPoint.proceed();System.out.println("YourAspect环绕通知结束");}@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidbeforeAdvice(){System.out.println("YourAspect前置通知");}@AfterReturning("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterReturningAdvice(){System.out.println("YourAspect后置通知");}@AfterThrowing("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterThrowingAdvice(){System.out.println("YourAspect异常通知");}@After("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterAdvice(){System.out.println("YourAspect最终通知");}}
packagecom.powernode.spring6.service;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;// 切面类@Component@Aspect@Order(2)//设置优先级publicclassMyAspect{@Around("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidaroundAdvice(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println("环绕通知开始");// 执行目标方法。proceedingJoinPoint.proceed();System.out.println("环绕通知结束");}@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidbeforeAdvice(){System.out.println("前置通知");}@AfterReturning("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterReturningAdvice(){System.out.println("后置通知");}@AfterThrowing("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterThrowingAdvice(){System.out.println("异常通知");}@After("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterAdvice(){System.out.println("最终通知");}}

执行测试程序:

通过修改@Order注解的整数值来切换顺序,执行测试程序:

优化使用切点表达式

观看以下代码中的切点表达式:

packagecom.powernode.spring6.service;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;// 切面类@Component@Aspect@Order(2)publicclassMyAspect{@Around("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidaroundAdvice(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println("环绕通知开始");// 执行目标方法。proceedingJoinPoint.proceed();System.out.println("环绕通知结束");}@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidbeforeAdvice(){System.out.println("前置通知");}@AfterReturning("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterReturningAdvice(){System.out.println("后置通知");}@AfterThrowing("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterThrowingAdvice(){System.out.println("异常通知");}@After("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidafterAdvice(){System.out.println("最终通知");}}

缺点是:

  • 第一:切点表达式重复写了多次,没有得到复用。
  • 第二:如果要修改切点表达式,需要修改多处,难维护。

可以这样做:将切点表达式单独的定义出来,在需要的位置引入即可。如下:

packagecom.powernode.spring6.service;importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.*;importorg.springframework.core.annotation.Order;importorg.springframework.stereotype.Component;// 切面类@Component@Aspect@Order(2)publicclassMyAspect{@Pointcut("execution(* com.powernode.spring6.service.OrderService.*(..))")publicvoidpointcut(){}@Around("pointcut()")publicvoidaroundAdvice(ProceedingJoinPointproceedingJoinPoint)throwsThrowable{System.out.println("环绕通知开始");// 执行目标方法。proceedingJoinPoint.proceed();System.out.println("环绕通知结束");}@Before("pointcut()")publicvoidbeforeAdvice(){System.out.println("前置通知");}@AfterReturning("pointcut()")publicvoidafterReturningAdvice(){System.out.println("后置通知");}@AfterThrowing("pointcut()")publicvoidafterThrowingAdvice(){System.out.println("异常通知");}@After("pointcut()")publicvoidafterAdvice(){System.out.println("最终通知");}}

使用@Pointcut注解来定义独立的切点表达式。
注意这个@Pointcut注解标注的方法随意,只是起到一个能够让@Pointcut注解编写的位置。
执行测试程序:

http://www.jsqmd.com/news/139929/

相关文章:

  • 外卖骑手实时就近派单全攻略:SpringBoot + GeoHash 高效实现
  • 我发现大文件HTTP上传阻塞 后来才知道用分块编码流式传输
  • 基于PSO-GA混合算法的施工进度计划多目标优化,以最小化总成本并实现资源均衡,满足工期约束和资源限制,MATLAB代码
  • Spring 7.0 与 Spring AI:Java 生态在 AI 时代的“绝对利器”
  • Java计算机毕设之基于VUE的旅游信息分享管理平台基于Springboot+Vue的旅游攻略分享平台系统(完整前后端代码+说明文档+LW,调试定制等)
  • (37)全注解式开发AOP
  • 揭开科立干冰清洗机神秘面纱:调试、能耗与研发能力解析 - 工业品网
  • 2025本科生必看!9个降AI率工具测评榜单
  • Java毕设项目:基于VUE的旅游信息分享管理平台(源码+文档,讲解、调试运行,定制等)
  • BMI160六轴惯性运动传感器原理图设计,已量产(加速度传感器)
  • 2025最新!专科生必看!8个AI论文平台测评,写毕业论文不再难
  • 微信小程序vue_uniapp研究生导师日常交互师生交流,考勤打卡任务,请假
  • 【鲲苍提效】一键批量接入外部应用监控,全面提升监控接入效率
  • BMM350三轴地磁传感器原理图设计,已量产(加速度传感器)
  • 4、索引有哪几种类型?
  • 从化房地产营销策划公司推荐:成本降低60%引爆热销潮 - 品牌测评家
  • PCIe-Tag字段与Outstanding Request
  • 海珠区心理咨询机构哪家好:权威榜单专业测评 - 品牌测评家
  • 实用指南:Redis底层数据结构 -- ziplist, quicklist, skiplist
  • hadoop 分布式集群启动命令 停止命令 hadoop jps查看每个节点状态命令
  • 基于贝叶斯优化的卷积神经网络-门控循环单元回归预测模型及评估指标 - BO-CNN-GRU B...
  • 探秘科立干冰清洗设备:高效靠谱之选 - 工业设备
  • 人工智能领域【专有名词汇总】...补充中...
  • 就想讨点学分有什么不队 - Beta冲刺
  • 科立干冰清洗机:,靠谱之选 - 工业品网
  • 不止溜背好看,这辆新奥迪还藏着“华为大脑”
  • 对比学习:【SimCLR】
  • ADXL345加速度传感器原理图设计,已量产(加速度传感器)
  • 全新帕萨特ePro前瞻:换了新平台、综合续航1300公里
  • 智谱MiniMax竞速上市,字节新模型数学推理突破,清华开源视频生成技术,AI监管政策出台