Spring AOP常用类:ProceedingJoinPoint、JoinPoint
在说到Spring框架,我们往往对Spring MVC
,Spring Web
更加熟悉。
Spring AOP
也是Spring
大家族中的一员。相比于机械的记忆,在实际做项目的过程中,我才真正的接触和应用到它,也理解了它的含义。
首先提到Spring AOP
,就不得不说到AOP
:面向切面编程。
关于它的定义有很多,这里无需赘述,总之在实际应用中,我们往往需要自己定义注解,编写切面类,比如下面的注解,我们要重写日志,以便于在控制台看到足够的信息。
自定义注解
package com.quanxiaoha.weblog.common.aspect;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface ApiOperationLog {
/**
* API 功能描述
*
* @return
*/
String description() default "";
}
在这个注解里,设置了一个默认的description为""
注解有了,我们需要编写切面类:
@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {
/** 以自定义 @ApiOperationLog 注解为切点,凡是添加 @ApiOperationLog 的方法,都会执行环绕中的代码 */
@Pointcut("@annotation(com.quanxiaoha.weblog.common.aspect.ApiOperationLog)")
public void apiOperationLog() {}
/**
* 环绕
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("apiOperationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
try {
... ...(省略)
// 获取被请求的类和方法
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
... ...
// 执行切点方法
Object result = joinPoint.proceed();
... ...
return result;
} finally {
MDC.clear();
}
}
}
这个切面类仅作示例,且源代码为我跟做的项目的源码,因此这里隐藏了部分,仅留下一些框架作为讲解。
由于这个是环绕型的,所以我们在编写的时候需要选用ProceedingJoinPoint
而不是JoinPoint
具体原因可以看方法体里的代码,首先要获取被请求的类和方法,然后执行一系列操作后还要继续执行注解方法joinPoint.proceed()
,然后再进行一系列操作。
由此,我们能够看出它的特点,就是它可以控制目标方法继续执行。
区别
ProceedingJoinPoint
和 JoinPoint
都是 Spring AOP
中的接口,用于在切面编程中获取方法的相关信息。它们的区别主要在于功能上,尤其是在环绕通知(@Around
)和其他通知(如前置通知、后置通知)中的使用方式。
JoinPoint 接口:
JoinPoint
是 Spring AOP
中最基础的接口,它代表了目标方法执行的一个“连接点”。JoinPoint
提供了对方法签名、参数等基本信息的访问。
主要功能:
- 获取目标方法的 签名(getSignature());
- 获取目标方法的 参数(getArgs());
- 获取目标方法的 目标类(getTarget());
- 获取当前连接点的 方法名(getSignature().getName())。
使用场景:
JoinPoint
一般用于 前置通知、后置通知 或 异常通知 等。这些通知不需要控制目标方法的执行流程。
示例:
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(JoinPoint joinPoint) {
// 获取方法名
String methodName = joinPoint.getSignature().getName();
// 获取参数
Object[] args = joinPoint.getArgs();
// 打印日志
System.out.println("Method name: " + methodName);
System.out.println("Arguments: " + Arrays.toString(args));
return null;
}
ProceedingJoinPoint 接口:
ProceedingJoinPoint
是 JoinPoint
的子接口,提供了比 JoinPoint
更多的功能,特别是在环绕通知中,用于继续执行目标方法。
主要区别:
继续执行目标方法:ProceedingJoinPoint
提供了一个proceed()
方法,该方法用于在环绕通知中继续执行目标方法,并且可以传递新的参数。如果你使用的是 JoinPoint
,就无法在通知中继续执行目标方法。
与 JoinPoint
相同的功能:ProceedingJoinPoint
继承了 JoinPoint
的所有基本功能,例如获取方法签名、方法参数等。
使用场景:
ProceedingJoinPoint
主要用于 环绕通知,因为只有环绕通知需要对目标方法的执行进行控制。
示例:
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 获取方法名
String methodName = proceedingJoinPoint.getSignature().getName();
// 获取参数
Object[] args = proceedingJoinPoint.getArgs();
// 打印日志
System.out.println("Method name: " + methodName);
System.out.println("Arguments: " + Arrays.toString(args));
// 执行目标方法
Object result = proceedingJoinPoint.proceed();
// 执行完毕后打印返回值
System.out.println("Result: " + result);
return result;
}
主要区别总结:
特性 | JoinPoint | ProceedingJoinPoint |
---|---|---|
功能 | 获取方法签名、参数等基本信息 | 获取方法签名、参数等基本信息,并且能够控制目标方法的执行 |
通知类型 | 用于前置通知、后置通知、异常通知等 | 仅用于环绕通知 |
是否可以控制目标方法执行 | 不可以 | 可以,通过 proceed() 方法继续执行目标方法 |
原文地址:https://blog.csdn.net/weixin_47510148/article/details/144041431
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!