Spring的第十二阶段(03):Spring实现AOP的简单使用

news2024/12/31 5:42:25

1、获取拦截方法的返回值和抛的异常信息

获取方法返回的值分为两个步骤:

1、在返回值通知的方法中,追加一个参数 Object result
2、然后在@AfterReturning注解中添加参数returning=“参数名”

获取方法抛出的异常分为两个步骤:

1、在异常通知的方法中,追加一个参数Exception exception
2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”

修改LogUtil切面类的代码

@AfterReturning(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
			+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", returning = "result")
	public static void logAfterReturn(JoinPoint joinPoint, Object result) {
		System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
	}

	@AfterThrowing(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"
			+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", throwing = "exception")
	public static void logThrowException(JoinPoint joinPoint, Exception exception) {
		System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
	}

测试结果

在这里插入图片描述

2、Spring的环绕通知

1、环绕通知使用@Around注解。
2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。
3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。
4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。

在LogUtil切面类中添加环绕通知

@Around(value = "execution(* *(..))")
	public static Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
		//获取请求参数
		Object[] args = proceedingJoinPoint.getArgs();
		Object resultObject = null;
		try {
			System.out.println("环绕前置");
			//调用目标方法
			resultObject = proceedingJoinPoint.proceed(args);
			System.out.println("环绕后置");
		} catch (Throwable e) {
			System.out.println("环绕异常:" + e);
			throw new RuntimeException(e);
		} finally {
			System.out.println("环绕返回后");
		}
		//返回返回值
		return resultObject;
	}

修改测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	private Calculator calculator;

	@Test
	public void test1() {
		//加法
		calculator.add(1, 2);
	}
}

执行结果

在这里插入图片描述

3、切入点表达式的重用

切入点表达式的重点,需要分三个步骤:

1、在切面类中定义一个空的方法

public static void pointcut1() {}

2、在方法中使用@Pointcut定义一个切入连表达式

@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
			+ "execution(public * com.atguigu.aop.Calculator.*(..))")
	public static void pointcut1() {}

3、其他的通知注解中使用方法名()的形式引用方法上定义的切入点表达式。
比如:@Before("pointcut1()")

4、多个通知的执行顺序

当有多个切面,多个通知的时候:

1、通知的执行顺序默认是由切面类的字母先后顺序决定。
2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)

再添加另一个切面类

@Component
@Aspect
@Order(1)
public class Validation {

	@Before(value = "com.atguigu.aop.LogUtil.pointcut1()")
	public static void before(JoinPoint joinPoint) {
		System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	@After(value = "com.atguigu.aop.LogUtil.pointcut1()")
	public static void after(JoinPoint joinPoint) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	@AfterReturning(value = "com.atguigu.aop.LogUtil.pointcut1()", returning = "result")
	public static void afterReturning(JoinPoint joinPoint, Object result) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
				+ ", 返回值:" + result);
	}

}

修改原来LogUtil中的切面内容(去掉环绕通知,留下前置,后置,返回后通知)

@Aspect
@Component
@Order(2)
public class LogUtil {
	@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "
			+ "execution(public * com.atguigu.aop.Calculator.*(..))")
	public static void pointcut1() {}

测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	private Calculator calculator;
	@Test
	public void test1() {
		//加法
		calculator.add(1, 0);
	}
}

运行的结果
在这里插入图片描述

5、如何基于xml配置aop程序

需要导入的包

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
log4j-1.2.17.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-test-4.0.0.RELEASE.jar

工程中编写的类

public class Calculator {
	public int div(int num1, int num2) {
		return num1 / num2;
	}

	public int add(int num1, int num2) {
		return num1 + num2;
	}
}

LogUtil切面类

public class LogUtil {
	public static void logBefore(JoinPoint joinPoint) {
		System.out.println("前置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用前 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()));
	}

	public static void logAfter(JoinPoint joinPoint) {
		System.out.println("后置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()));
	}

	public static void logAfterReturn(JoinPoint joinPoint, Object result) {
		System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);
	}

	public static void logThrowException(JoinPoint joinPoint, Exception exception) {
		System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"
				+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);
	}
}

Validation切面类

public class Validation {
	public static void before(JoinPoint joinPoint) {
		System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	public static void after(JoinPoint joinPoint) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());
	}

	public static void afterReturning(JoinPoint joinPoint, Object result) {
		System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()
				+ ", 返回值:" + result);
	}
}

ApplicationContext.xml配置文件中的内容

<!-- 注册bean对象
		添加@Component
	 -->
	<bean id="calculator" class="com.atguigu.aop.Calculator" />
	<bean id="logUtil" class="com.atguigu.aop.LogUtil" />
	<bean id="validation" class="com.atguigu.aop.Validation" />
	<!-- 配置AOP -->
	<aop:config>
		<!-- 定义可以共用的切入点 -->
		<aop:pointcut expression="execution(* com.atguigu.aop.Calculator.*(..))" id="pointcut1"/>
		<!-- 定义切面类 -->
		<aop:aspect order="1" ref="logUtil">
			<!-- 这是前置通知 
					method属性配置通知的方法
					pointcut配置切入点表达式
			 -->
			<aop:before method="logBefore" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after method="logAfter" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after-returning method="logAfterReturn" 
				returning="result" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
			<aop:after-throwing method="logThrowException" throwing="exception"
				pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/>
		</aop:aspect>
		<!-- 定义切面类 -->
		<aop:aspect order="2" ref="validation">
			<aop:before method="before" pointcut-ref="pointcut1"/>
			<aop:after method="after" pointcut-ref="pointcut1"/>
			<aop:after-returning method="afterReturning" 
				returning="result" pointcut-ref="pointcut1"/>
		</aop:aspect>
	</aop:config>

测试的代码

@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
	@Autowired
	Calculator calculator;
	@Test
	public void test1() {
		calculator.add(1, 2);
	}
}

测试运行的结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python入门(五)列表(二)

列表&#xff08;二&#xff09; 1.组织列表1.1 使用方法sort()对列表永久排序1.2 使用函数sorted()对列表临时排序1.3 倒着打印列表1.4 确定列表的长度1.5 使用列表时避免索引错误 2.操作列表2.1 遍历整个列表2.1.1 for循环2.1.2 在for循环中执行更多操作2.1.3 在for循环结束后…

用C语言编写,计算并输出下列多项式值 s=1+1/(1+2)+1/(1+2+3)+ ..1/(1+2+3...+50)

C/C语言程序设计题目 用C语言编写&#xff0c;计算并输出下列多项式值 s11/(12)1/(123) …1/(123…50) C语言设计编程代码 #include <stdio.h>int main() {double s 0; // 初始化s的值为0int n 0; // 初始化n的值为0for (int i 1; i < 50; i) {n i; // 累加n的…

scatterlist

在内核驱动程序的很多代码中&#xff0c;都能够看到类似sgdma的内容&#xff0c;sgdma全称为Scatter/Gather DMA(散列/收集 DMA)&#xff0c;内核中抽象了scatterlist和sg table用来描述和管理这种需要做散列和收集的DMA缓冲区。在内核中设计scatterlist&#xff0c;主要出于两…

BDCC - Lambda VS Kappa

文章目录 概述区别Lambda架构:Kappa架构:总结 适用场景:案例:小结 概述 Lambda架构和Kappa架构都是用于处理大数据的架构模式。 Lambda架构使用了批处理和流处理两种不同的处理方式来处理数据。数据首先通过流处理层进行实时处理&#xff0c;然后再通过批处理层进行离线处理&…

开源C#代码生成器,SmartSoftHelp 开发辅助工具

开源代码生成器&#xff0c;支持自定义生成代码&#xff0c;开源生成代码&#xff0c;自己编写生成格式&#xff0c;最方便的代码生成器 下载地址&#xff1a; 百度网盘 请输入提取码

《时间从来不语,却回答了所有问题》笔记三

目录 感悟 经典摘录 假若我再上一次大学 不完满才是人生 走运与倒霉 毁誉 我的座右铭 二月兰 观天池 火车上观日出 感悟 人这个万物之灵却偏偏有了感情&#xff0c;有了感情就有了悲欢。自古及今&#xff0c;海内海外&#xff0c;一个百分之百完满的人生是没有的&…

《Java虚拟机学习》JVM虚拟机是如何执行方法

1. 重载与重写方法 重载 重载 &#xff1a;同一个类中&#xff0c;方法名相同&#xff0c;形参列表不用&#xff0c;与返回值无关 对于重载方法的执行&#xff0c;JVM遵循下面的三条规则&#xff1a; 在不考虑对基本类型自动装拆箱&#xff08;auto-boxing&#xff0c;auto-…

图嵌入表示学习—Graph Embeddings

Embedding Entire Graphs 一、图嵌入向量基本概念 与Node Embeddings不同&#xff0c;Graph Embeddings是对整个图或子图进行编码而忽略其中的节点。应用场景包括异常检测或分子有毒检测。 二、对Node Embeddings求和或求和后平均 如图&#xff0c;首先对图/子图中的节点进行…

shell与shell script 学习总结

文章目录 shell与shell script 学习总结vivim可视化区块多文件编辑多窗口功能vim环境设置与记录中文编码问题语系编码转换 Shell的变量功能变量的使用与设置echo(变量的使用)变量设置的规则 环境变量的功能env(观察环境变量)set(观察所有变量)unset(取消变量) locale(语系变量)…

【Hello Network】TCP协议相关理解

作者&#xff1a;小萌新 专栏&#xff1a;网络 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;补充下对于TCP协议的各种理解 TCP协议相关实验 TCP相关试验理解CLOSE_WAIT状态理解TIME_WAIT状态解决TIME_WAIT状态引起的bind失败的方法理解listen的…

分布式 03 富文本处理插件和图片文件上传

01.使用富文本编辑器来上传图片文件。 02.最开始在html文件中去使用相关富文本的插件。 引入相关文件 <link href"/js/kindeditor-4.1.10/themes/default/default.css" type"text/css" rel"stylesheet"> <script type"text/java…

Redis面试题(上)

1.什么是 Redis&#xff1f; Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景&#xff0c;比如 Strin…

Python机器学习入门 -- 支持向量机学习笔记

文章目录 前言一、支持向量机简介二、支持向量机的数学原理1. 距离解算2. 目标函数3. 约束下的优化求解4. 软间隔优化5. 核函数变换 三、Python实现支持向量机1. 惩罚力度对比2. 高斯核函数3. 非线性SVM 总结 前言 大部分传统的机器学习算法都可以实现分类任务&#xff0c;但这…

干货丨你真的了解反应持续时间吗?

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 在今天的推文里&#xff0c;要给大家分享的是一种灵活、免费的心理科学工具——反应持续时间&#xff0c;快来一起看看哦~ 01 导读 简单按键的反应持续时间是一种容易获得但未被充分利用…

C++相比于C语言增加的8个小特性(详解)

C相比于C语言增加的8个小特性&#xff08;详解&#xff09; 文章目录 C相比于C语言增加的8个小特性&#xff08;详解&#xff09;一、命名空间二、C输入和输出三、缺省参数四、函数重载五、引用六、内联函数七、auto关键字八、指针空值nullptr总结 一、命名空间 c的命名空间是…

从一到无穷大 #8 Arrow,Parquet and ORC

文章目录 引言ArrowParquetNested EncodingRepetition LevelsDefinition Levels 列化压缩 ORC 引言 以我的机器为例来做一个简单的计算&#xff1a; 执行cat /proc/cpuinfo |grep MHz|uniq可以看到目前机器中CPU频率&#xff0c;得到值 2494.140MHZ&#xff5e;2494140000HZ&…

【算法】——全排列算法讲解

前言&#xff1a; 今天&#xff0c;我给大家讲解的是关于全排列算。我会从三个方面去进行展开&#xff1a; 首先&#xff0c;我会给大家分析关于全排列算法的思想和定义&#xff1b;紧接着通过手动实现出一个全排列代码来带大家见见是怎么实现的&#xff1b;最后我会给出两道题…

ESP32单片机入门篇

目录 一、ESP32单片机的基本概念 1.双核架构 2. Wi-Fi和蓝牙功能 3. 集成多种外设 4. 支持多种操作系统 二、开发环境 1. Arduino IDE 2. ESP-IDF 三、开发语言 四、注意事项 五、代码例程 &#xff08;1&#xff09;点亮LED灯 1. 电路图 2. 代码 3. 代码注释 …

【精品】Java-Stream流详解

Java-Stream流详解 如何学会JDK8中的Stream流&#xff0c;用它来提高开发效率&#xff1f;创建不可变的集合&#xff08;Immutable 不可变的&#xff09;场景方法 初试 Stream 流Stream 流的思想Stream 流的作用Stream 流的使用步骤Stream 流的中间方法Stream 流的终结方法 如何…

STM32:利用PWM波控制飞盈电调过程和注意事项

STM32&#xff1a;利用PWM波控制电调过程和注意事项 在进行模型控制的过程中&#xff0c;如四旋翼无人机等&#xff0c;需要用到电机&#xff0c;这些电机需要通过电调来控制电机的转速。在电调模块中带有的说明书一般都是利用遥控器进行控制&#xff0c;有些情况需要自己通过…