Spring - AOP - 通知
1. 前置通知
@Before()
:在一个方法执行之前,执行通知。
/**
* 前置通知,在目标方法执行之前执行。
* 该注解使用AOP表达式指定通知应用于com.springaop.service.UserService包中所有方法的执行。
*
* @param joinPoint 切点,包含关于执行方法的信息,如方法名、参数等。
*/
@Before("execution(* com.springaop.service.UserService.*(..))")
public void before(JoinPoint joinPoint) {
// 获取当前执行的方法名
String name = joinPoint.getSignature().getName();
// 获取方法参数列表
Object[] args = joinPoint.getArgs();
// 获取目标对象,即被通知的对象
Object target = joinPoint.getTarget();
// 打印日志,记录方法执行前的信息
System.out.println("前置通知:" + name + "方法执行前,参数为:" + Arrays.toString(args) + ",目标对象为:" + target);
}
程序输出:
前置通知:addUser方法执行前,参数为:[1],目标对象为:com.springaop.service.UserService@1ec9bd38
addUser:1
2. 后置通知
@After()
:在一个方法执行之后,不考虑其结果,执行通知。
/**
* 后置通知,在UserService接口的任何方法执行后调用。
* 该注解使用AOP表达式指定通知的触发条件,即匹配UserService接口的所有方法。
* 主要用于记录方法执行后的相关信息。
*
* @param joinPoint 切点对象,包含关于执行方法的信息,如方法名、参数等。
*/
@After("execution(* com.springaop.service.UserService.*(..))")
public void after(JoinPoint joinPoint) {
// 获取方法名
String name = joinPoint.getSignature().getName();
// 获取方法参数
Object[] args = joinPoint.getArgs();
// 获取目标对象
Object target = joinPoint.getTarget();
// 打印后置通知信息,包括方法名、参数和目标对象
System.out.println("后置通知:" + name + "方法执行后,参数为:" + Arrays.toString(args) + ",目标对象为:" + target);
}
程序输出:
addUser:1
后置通知:addUser方法执行后,参数为:[1],目标对象为:com.springaop.service.UserService@4b2c5e02
3. 异常通知
@AfterThrowing()
:在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
/**
* 异常处理的切面逻辑。
* 该方法在UserService接口的实现方法执行过程中发生异常时被调用。
* 主要用于记录方法执行时出现的异常信息,包括方法名称、参数、目标对象和异常消息。
*
* @param joinPoint 切点,包含关于正在执行的方法和目标对象的信息。
* @param ex 异常对象,代表在方法执行过程中发生的异常。
*/
@AfterThrowing(pointcut = "execution(* com.springaop.service.UserService.*(..))", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
// 获取当前执行方法的名称
String name = joinPoint.getSignature().getName();
// 获取方法参数
Object[] args = joinPoint.getArgs();
// 获取目标对象
Object target = joinPoint.getTarget();
// 打印异常通知信息,包括方法名称、参数、目标对象和异常消息
System.out.println("异常通知:" + name + "方法执行后,参数为:" + Arrays.toString(args) + ",目标对象为:" + target + ",异常信息为:" + ex.getMessage());
}
程序输出:
addUser:1
异常通知:addUser方法执行后,参数为:[1],目标对象为:com.springaop.service.UserService@2415fc55,异常信息为:addUser error
4. 返回通知
@AfterReturning()
:在一个方法执行之后,只有在方法成功完成时,才能执行通知。
/**
* 后置返回通知,用于在UserService接口的任意方法执行完成后执行。
* 该通知将打印方法名、方法参数、目标对象和方法返回值的信息。
*
* @param joinPoint 切点,包含关于执行方法的信息,如方法名、参数等。
* @param result 方法的返回值,用于在通知中进行操作或记录。
*/
@AfterReturning(pointcut = "execution(* com.springaop.service.UserService.*(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
// 获取方法名
String name = joinPoint.getSignature().getName();
// 获取方法参数
Object[] args = joinPoint.getArgs();
// 获取目标对象
Object target = joinPoint.getTarget();
// 打印方法执行后的相关信息
System.out.println("返回通知:" + name + "方法执行后,参数为:" + Arrays.toString(args) + ",目标对象为:" + target + ",返回值为:" + result);
}
程序输出:
addUser:1
返回通知:addUser方法执行后,参数为:[1],目标对象为:com.springaop.service.UserService@34b9f960,返回值为:null
5. 环绕通知
@Around()
:在建议方法调用之前和之后,执行通知。
/**
* 基于AOP的切面逻辑,围绕UserService中的方法执行。
* 使用@Around注解可以控制方法执行前、执行后以及出现异常时的行为。
*
* @param joinPoint 切点对象,包含关于目标方法的信息,可以用来调用目标方法。
* @return 返回目标方法的执行结果。如果执行过程中发生异常,可能会返回null。
* @throws Throwable 如果目标方法执行过程中抛出异常,这里会重新抛出。
*/
@Around("execution(* com.springaop.service.UserService.*(..))")
public Object around(ProceedingJoinPoint joinPoint) {
// 前置通知:在目标方法执行前执行的操作
// region 前置通知
System.out.println("前置通知");
// endregion
try {
// 执行目标方法
// region 目标方法
Object result = joinPoint.proceed();
// endregion
// 返回通知:在目标方法正常返回后执行的操作
// region 返回通知
System.out.println("返回通知:" + result);
return result;
// endregion
} catch (Throwable e) {
// 异常通知:在目标方法抛出异常时执行的操作
// region 异常通知
System.out.println("异常通知:" + e.getMessage());
// endregion
} finally {
// 后置通知:无论目标方法执行是否成功,都会执行的操作
// region 后置通知
System.out.println("后置通知");
// endregion
}
// 如果执行流程走到这里,通常是因为目标方法抛出异常且被catch住,或者在try块中的proceed()之前发生异常。
// 返回null表示方法执行失败。
return null;
}
6. 执行顺序
- 程序正常:前置通知 ===> 目标方法 ===> 返回通知 ===> 后置通知(finally)
- 程序异常:前置通知 ===> 目标方法 ===> 异常通知 ===> 后置通知(finally)