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

news/2024/11/23 3:41:46/

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 {@Autowiredprivate Calculator calculator;@Testpublic 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 {@Autowiredprivate Calculator calculator;@Testpublic 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 {@AutowiredCalculator calculator;@Testpublic void test1() {calculator.add(1, 2);}
}

测试运行的结果

在这里插入图片描述


http://www.ppmy.cn/news/61040.html

相关文章

【力扣周赛】第344场周赛

【力扣周赛】第344场周赛 6416&#xff1a;找出不同元素数目差数组题目描述解题思路 6417&#xff1a;频率跟踪器题目描述解题思路 6418&#xff1a;有相同颜色的相邻元素数目题目描述解题思路 6419&#xff1a;使二叉树所有路径值相等的最小代价题目描述解题思路 6416&#xf…

linux【网络编程】之网络基础

linux【网络编程】之网络基础 一、网络协议与协议分层1.1 为什么要分层1.2 OSI七层模型1.3 TCP/IP五层(或四层)模型 二、网络传输流程2.1 了解局域网2.2 同一网段内的两台主机进行文件传输2.3 跨网段的主机的文件传输 三、数据包封装和分用四、网络中的地址管理4.1 IP地址4.2 M…

【Leetcode -383.赎金信 -387.字符串中的第一个唯一字符】

Leetcode Leetcode -383.赎金信Leetcode - 387.字符串中的第一个唯一字符 Leetcode -383.赎金信 题目&#xff1a;给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#x…

gtest之primer

目录 准备工作测试宏两个概念Test Fixturesmain函数关于线程安全 准备工作 GoogleTest官网&#xff1a;https://google.github.io/googletest/ gtest github仓库&#xff1a;https://github.com/google/googletest 目前最新稳定版本&#xff1a;https://github.com/google/goo…

手动实现 Spring 底层机制【初始化 IOC容器+依赖注入+BeanPostProcessor 机制+AOP】

目录 手动实现 Spring 底层机制【初始化 IOC容器依赖注入BeanPostProcessor 机制AOP】 前面我们实际上已经用代码简单实现了 代码演示使用框架 创建一个maven项目 创建UserAction类 创建UserDao类 创建UserService类 创建beans.xml 说明 创建AppMain类 运行效果 如图…

python处理图像的各种技术镜像、旋转、遮挡、叠加、条带化

2.6 图像镜面对称 1、将图像水平镜面转换。 2、将图像垂直镜面转换。 import random #导入模块 import numpy as np import matplotlib.pyplot as plt a plt.imread("1.jpg") # 将图像沿着水平方向重复三次。 ba.copy() da.copy() # 将图像水平镜面转换。&…

对象浅拷贝的5种方式

参考原文:浅拷贝的五种实现方式 - 掘金 (juejin.cn) 哈喽 大家好啊 最近发现自己对对象都不是很熟练&#xff0c;特别是涉及到一些复制&#xff0c;深浅拷贝的东西 1.Object.assign 首先 我们创建一个空对象obj1 然后创建一个对象obj2 用object.assign(目标对象&#xff0c…

Java --- String类

&#xff08;一&#xff09;String java.lang.String 类代表字符串。Java 程序中所有的字符串文字&#xff08;例如 "hello" &#xff09;都可以看作是实现此类的实例。 字符串是常量&#xff0c;用双引号引起来表示。它们的值在创建之后不能更改。 字符串 St…