自学内容网 自学内容网

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;
}

主要区别总结:

特性JoinPointProceedingJoinPoint
功能获取方法签名、参数等基本信息获取方法签名、参数等基本信息,并且能够控制目标方法的执行
通知类型用于前置通知、后置通知、异常通知等仅用于环绕通知
是否可以控制目标方法执行不可以可以,通过 proceed() 方法继续执行目标方法

原文地址:https://blog.csdn.net/weixin_47510148/article/details/144041431

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!