【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异常
    介绍完这么多种通知类型,具体该选哪一种呢?
    下一章节,我们可以通过一些案例加深下对通知类型的学习

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu如何远程ssh登录Windows环境并执行测试命令

ubuntu如何远程ssh登录Windows环境并执行测试命令 1 paramiko模块简介1.1 安装paramiko1.2 paramiko基本用法1.2.1 创建SSHClient实例1.2.2 设置主机密钥策略1.2.3 连接SSH服务器1.2.4 执行命令1.2.5 关闭SSH连接1.2.6 异常处理 2 windows的配置2.1 启动OpenSSH服务2.2 配置防火…

JMeter直连数据库

JMeter直连数据库 使用场景操作步骤 使用场景 用作请求的参数化 登录时需要的用户名,密码可以从数据库中查询获取 用作结果的断言 添加购物车下订单,检查接口返回的订单号,是否与数据库中生成的订单号一致 清理垃圾数据 添加商品后&#xff…

Gin之GORM 操作数据库(MySQL)

GORM 简单介绍 GORM 是 Golang 的一个 orm 框架。简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping) 的缩写。使用 ORM框架可以让我们更方便…

Kotlin+Apache HttpClient+代理服务器=高效的eBay图片爬虫

引入 你是否想过用Kotlin来编写爬虫程序?你是否想过用Apache HttpClient来处理HTTP请求和响应?你是否想过用代理服务器来绕过反爬措施?如果你的答案是肯定的,那么本文将为你介绍一种高效的eBay图片爬虫的实现方式,让你…

深入理解 Kafka 集群管理与最佳实践

构建和管理一个稳定、高性能的Kafka集群对于实现可靠的消息传递至关重要。本文将深入研究Kafka集群的各个方面,包括集群搭建、节点配置、分区与副本管理、安全性与监控,为读者提供全面的指导和实例代码。 1. 搭建 Kafka 集群 1.1 Broker 节点 在Kafka…

C++11 【初识】

C11简介 1.在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1),使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。 2.不过由于C03(TC1)主要是对C98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合…

java版Spring Cloud+Spring Boot+Mybatis之隐私计算 FATE - 多分类神经网络算法测试

一、说明 本文分享基于 Fate 使用 横向联邦 神经网络算法 对 多分类 的数据进行 模型训练,并使用该模型对数据进行 多分类预测。 二分类算法:是指待预测的 label 标签的取值只有两种;直白来讲就是每个实例的可能类别只有两种 (0 或者 1)&…

【运维】Kafka高可用: KRaft(不依赖zookeeper)集群搭建

文章目录 一. kafka kraft 集群介绍1. KRaft架构2. Controller 服务器3. Process Roles4. Quorum Voters 二. 集群安装1. 安装1.1. 配置1.2. 格式化 2. 启动测试2.1. 启功节点服务2.2. 测试 本文主要介绍了 kafka raft集群架构: 与旧架构的不同点,有哪些…

ISP去噪(2)_np 噪声模型

#灵感# ISP 中的去噪,都需要依赖一个噪声模型。很多平台上使用采集的raw进行calibration,可以输出这个模型,通常称为 noise profile。 名词解释: Noise profile 似乎可以翻译成“噪声档案”,其含义是某个噪声源&…

昇腾910安装驱动出错,降低Centos7.6的内核版本

零、问题描述: 在安装Atlas800-9000服务器的驱动的时候,可能会出现错误:Dkms install failed, details in : /var/log/ascend_seclog/ascend_install.log 如下所示: [rootlocalhost ~]# ./Ascend-hdk-910-npu-driver_23.0.rc3_l…

数字孪生项目的开发框架

数字孪生的开发框架提供了一套工具和API,使开发者能够创建和管理数字孪生模型。这些框架通常包括虚拟建模、仿真、数据集成和分析等功能。以下是一些常见的数字孪生开发框架,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发…

python matplotlib set_aspect

说明: # 设置轴比例相等,以获得圆柱体视角 ax.set_aspect(equal) 代码案例: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np# 创建数据 theta np.linspace(0, 2*np.pi, 100) z np.linspace(0, 1, 100) r z**2 …

k8s集群部署及可视化kuboard 部署

目录 一.准备环境 1.准备三台服务器 2.做域名解析[集群] 3.时间同步[集群] 4.关闭防火墙与selinux[集群] 5.配置静态ip[集群] 6.关闭swap分区[集群] 7.注意: 二.docker部署[集群] 2.安装最新版 3.查看Docker版本: 4.启动Docker服务&#xff1…

maui sqlite开发一个商城加购物车的演示(3)

购物车界面及代码 <?xml version"1.0" encoding"utf-8" ?> <ContentPage xmlns"http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x"http://schemas.microsoft.com/winfx/2009/xaml"xmlns:syncfusion"clr-namesp…

基于51单片机的语音识别控制系统

0-演示视频 1-功能说明 &#xff08;1&#xff09;使用DHT11检测温湿度&#xff0c;然后用LCD12864显示&#xff0c;语音播放&#xff0c;使用STC11l08xe控制LD3320做语音识别&#xff0c; &#xff08;2&#xff09;上电时语音提示&#xff1a;欢迎使用声音识别系统&#xf…

微信小程序改变checkbox大小

.weui-cell__hd {transform: scale(0.6,0.6);} <checkbox color"#447189" />

Qt12.12

头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime> #include <QTimer> #include <QTimerEvent> #include <QTextToSpeech> //文本转语言类QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_…

Dockerfile创建镜像--LNMP+wordpress

实验准备&#xff1a; nginx&#xff1a;172.111.0.10 docker-nginx mysql&#xff1a;172.111.0.20 docker-mysql php&#xff1a;172.111.0.30 docker-php 自定义网段&#xff1a;172.111.0.0/16mkdir nginx mysql php mv nginx-1.22.0.tar.gz wordpress-6.4.2-zh_CN.ta…

Java实现选择排序及其动图演示

选择排序是一种简单直观的排序算法。它的基本思想是每次从未排序的元素中选出最小&#xff08;或最大&#xff09;的元素&#xff0c;然后将其放到已排序的序列的末尾。具体步骤如下&#xff1a; 首先&#xff0c;找到未排序序列中的最小&#xff08;或最大&#xff09;元素&a…

Linux实用操作(超级实用)

Linux实用操作篇-上篇&#xff1a;Linux实用操作-上篇-CSDN博客 Linux实用操作篇-下篇&#xff1a;Linux实用操作篇-下篇-CSDN博客 一、各类小技巧&#xff08;快捷键&#xff09; 1.1 ctrl c 强制停止 Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以…