【Spring教程17】Spring框架实战:实例详解解读AOP通知类型的使用

欢迎大家回到《Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《AOP配置管理中AOP切入点表达式和通知类型》

在这里插入图片描述

本文的示例代码均来自之前AOP的相关博博文,没有示例代码的C友,请移步《Spring教程13》开始看起

1、前置通知

修改MyAdvice,在before方法上添加@Before注解

@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Before("pt()")//此处也可以写成 @Before("MyAdvice.pt()"),不建议public void before() {System.out.println("before advice ...");}
}

在这里插入图片描述

2、后置通知

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Before("pt()")public void before() {System.out.println("before advice ...");}@After("pt()")public void after() {System.out.println("after advice ...");}
}

在这里插入图片描述

3、环绕通知

基本使用

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Around("pt()")public void around(){System.out.println("around before advice ...");System.out.println("around after advice ...");}
}

在这里插入图片描述
运行结果中,通知的内容打印出来,但是原始方法的内容却没有被执行。

因为环绕通知需要在原始方法的前后进行增强,所以环绕通知就必须要能对原始操作进行调用,具体
如何实现?

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Around("pt()")public void around(ProceedingJoinPoint pjp) throws Throwable{System.out.println("around before advice ...");//表示对原始操作的调用pjp.proceed();System.out.println("around after advice ...");}
}

**说明:**proceed()为什么要抛出异常?
原因很简单,看下源码就知道了
在这里插入图片描述
再次运行,程序可以看到原始方法已经被执行了
在这里插入图片描述
注意事项
(1)原始方法有返回值的处理

  • 修改MyAdvice,对BookDao中的select方法添加环绕通知,
@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}@Around("pt2()")public void aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用pjp.proceed();System.out.println("around after advice ...");}
}
  • 修改App类,调用select方法
public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);BookDao bookDao = ctx.getBean(BookDao.class);int num = bookDao.select();System.out.println(num);}
}

运行后会报错,错误内容为:
Exception in thread “main” org.springframework.aop.AopInvocationException:
‘Null return value from advice does not match primitive return type for:
public abstract int com.itheima.dao.BookDao.select()’ at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:226) at com.sun.proxy.$Proxy19.select(Unknown Source) at com.itheima.App.main(App.java:12)

错误大概的意思是:空的返回不匹配原始方法的int返回

  • void就是返回Null
  • 原始方法就是BookDao下的select方法

所以如果我们使用环绕通知的话,要根据原始方法的返回值来设置环绕通知的返回值,具体解决方案
为:

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}@Around("pt2()")public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用Object ret = pjp.proceed();System.out.println("around after advice ...");return ret;}
}

说明:
为什么返回的是Object而不是int的主要原因是Object类型更通用。
在环绕通知中是可以对原始方法返回值就行修改的。
返回后通知

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}@AfterReturning("pt2()")public void afterReturning() {System.out.println("afterReturning advice ...");}
}

在这里插入图片描述
**注意:**返回后通知是需要在原始方法select正常执行后才会被执行,如果select()方法执行的过程
中出现了异常,那么返回后通知是不会被执行。后置通知是不管原始方法有没有抛出异常都会被执
行。这个案例大家下去可以自己练习验证下。
异常后通知

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}@AfterReturning("pt2()")public void afterThrowing() {System.out.println("afterThrowing advice ...");}
}

在这里插入图片描述
**注意:**异常后通知是需要原始方法抛出异常,可以在select()方法中添加一行代码int i = 1/0即可。如果没有抛异常,异常后通知将不会被执行。
学习完这5种通知类型,我们来思考下环绕通知是如何实现其他通知类型的功能的?
因为环绕通知是可以控制原始方法执行的,所以我们把增强的代码写在调用原始方法的不同位置就可以实现不同的通知类型的功能,如:
在这里插入图片描述

4、通知类型总结

知识点1:@After
在这里插入图片描述
知识点2:@AfterReturning
在这里插入图片描述
知识点3:@AfterThrowing
在这里插入图片描述
知识点4:@Around
在这里插入图片描述
环绕通知注意事项

  1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法
    调用前后同时添加通知
  2. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
  3. 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,最好设定为
    Object类型
  4. 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成
    Object
  5. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理Throwable异常
    介绍完这么多种通知类型,具体该选哪一种呢?
    下一章节,我们可以通过一些案例加深下对通知类型的学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/215834.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

现代雷达车载应用——第2章 汽车雷达系统原理 2.2节

经典著作,值得一读,英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.2 汽车雷达架构 从顶层来看,基本的汽车雷达由发射器,接收器和天线组成。图2.2给出了一种简化的单通道连续波雷达结构[2]。这…

[湖湘杯 2021 final]MultistaeAgency

文章目录 题目是给了源码,我们先来看web的main.go package mainimport ("bytes""crypto/md5""encoding/json""fmt""io""io/ioutil""log""math/rand""net/http""o…

存储成本降71%,怪兽充电历史库迁移OceanBase

怪兽充电作为共享充电宝第一股,业务增长迅速,以至于业务架构不停地增加组件。在验证 OceanBase 可以简化架构并带来更大的业务价值后,首次尝试在历史库中使用 OceanBase 替代 MySQL,存储成本降低 71%。本文为怪兽充电运维架构部王…

odoo自定义提示性校验

背景: 在odoo16的原生的代码里,可以给按钮添加一个 confirm属性,从而达到 提示性校验的效果。 问题: 这个属性加了之后一定会弹出提示性校验的对话框,于是如何根据我们的实际业务,从后端返回提示性信息,…

ubuntu 20.04.6 server 服务器 下载与安装(配置静态IP)

下载地址:https://releases.ubuntu.com/20.04.6/ubuntu-20.04.6-live-server-amd64.iso 第一步: 准备U盘,使用软碟通将下载好的镜像写入到U盘中 软碟通网址:https://www.cn.ultraiso.net/xiazai.html 点击:文件 ->…

matlab 最小二乘拟合空间直线(方法三)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接博客长期更新,GPT与爬虫自重,你也未必能爬到最新版本。 一、算法原理 1、算法过程 空间直线的点向式方程为:

远程服务器QEMU+Ubuntu+GRUB+VNC最佳实践

远程服务器QEMUUbuntuGRUBVNC最佳实践 1. 准备2. QEMU启动安装Ubuntu2.1 服务器端2.2 本地端 3. 从服务器终端控制虚拟机GRUB与虚拟机终端 这段时间参与大量内核切换测试工作,实体机需要硬件自检太过笨重,因此主要通过QEMU验证正确性。有一个很大的问题是…

OpenSSL 编程指南

目录 前言初始化SSL库创建SSL 上下文接口(SSL_CTX)安装证书和私钥加载证书(客户端/服务端证书)加载私钥/公钥加载CA证书设置对端证书验证例1 SSL服务端安装证书例2 客户端安装证书创建和安装SSL结构建立TCP/IP连接客户端创建socket服务端创建连接创建SSL结构中的BIOSSL握手服务…

Reinfocement Learning 学习笔记PartⅠ

文章目录 Reinfocement Learning一、基本概念二、贝尔曼公式(bellman equation)2.1 为什么return重要2.2 state value function的定义2.3 贝尔曼公式推导2.4 如何求解贝尔曼公式2.5 Action value的定义 三、贝尔曼最优公式(bellman optimalit…

1841_在Windows上安装emacs irony server

Grey 全部学习内容汇总:GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1841_在Windows上安装emacs irony server emacs有很多优点,配置出来不仅用着顺手而且有一定的成就感。但是,对于大多数人来说或…

将单体应用程序迁移到微服务

多年来,我处理过多个单体应用,并将其中一些迁移到了微服务架构。我打算写下我所学到的东西以及我从经验中用到的策略,以实现成功的迁移。在这篇文章中,我将以AWS为例,但基本原则保持不变,可用于任何类型的基…

【动态规划精选题目】1、斐波那契数列模型

此动态规划系列主要讲解大约10个系列【后续持续更新】 本篇讲解入门级:斐波那契模型,会在讲解题目同时给出AC代码 为什么叫斐波那契数列模型?因为本篇4道题的状态转移方程都跟斐波那契递推方程差不多,但这点不重要,请往…

【C++】:set和map

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关多态的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数据结…

补充回答一些关于枚举类型的问题

补充回答一些关于枚举类型的问题 1.枚举类型在什么时候使用 枚举类型在以下情况下特别有用: 有限的离散值集合: 当变量的取值只有有限且离散的几个选项时,使用枚举类型能够提高代码的可读性。例如,星期几、月份、颜色等。 enum W…

Uncaught ReferenceError: jQuery is not defined解决方法

当我在写java的Maven项目时,出现了这样的一个报错信息: 我一直找代码,抓包,调试,比对代码 jQuery未定义就是指JS的导包没有导进来!!!! 导进来就运行正常啦

Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 is available

记录一次服务调用中的错误 背景:我使用了nacos2.x的版本,同时在同一台服务器的三个docker容器中部署了nacos1、2、3,并将它们连接到了同一个docker网络 错误:Server check fail, please check server xxx.xxx.xxx.xxx,port 9848 …

使用cmake构建Qt6.6的qt quick项目,添加应用程序图标的方法

最近,在学习qt的过程中,遇到了一个难题,不知道如何给应用程序添加图标,按照网上的方法也没有成功,后来终于自己摸索出了一个方法。 1、准备一张图片作为图标,保存到工程目录下面,如logo.ico。 …

主机访问Android模拟器网络服务方法

0x00 背景 因为公司的一个手机app的开发需求,要尝试链接手机开启的web服务。于是在Android Studio的Android模拟器上尝试连接,发现谷歌给模拟器做了网络限制,不能直接连接。当然这个限制似乎从很久以前就存在了。一直没有注意到。 0x01 And…

Python编程技巧 – 使用组合运算符

Python编程技巧 – 使用组合运算符 Python Programming Skills – Using Combined Operators Python通过赋值过程,将声明变量与赋值和而为之,可谓讲求效率。此外,在Python赋值运算符里,也有一个强大高效的功能,即复合…

赴美上市传闻再起,SHEIN走到十字路口

作者 | 辰纹 来源 | 洞见新研社 裹挟着“黑五”大胜的余波,跨境电商巨头SHEIN(希音)将赴美IPO的传闻又在行业中散播开来。 金融投资报称SHEIN此次IPO的估值或达900亿美元;上海证券报表示,SHEIN已对投资人发出了路演…