AOP面向切面编程

今日需要使用自定义注解来完善接口的权限功能,想到了使用使用AOP来完成,AOP可以增强原始方法,使用代理对象在原始方法执行根据通知来完成方法的增强。

AOP 常用的注解和解释

在使用面向切面编程(AOP)时,常用的注解有以下几种:

  • @Aspect:将一个类标记为切面类。该注解通常与其他注解一起使用,用于定义切面逻辑。
  • @Pointcut:定义一个可重用的切点,一般用于方法级别的注解,表示匹配哪些方法可以被增强;
  • @Before:在目标方法执行之前执行通知(前置通知)。
  • @After:在目标方法执行之后(无论是否发生异常)执行通知(后置通知)。
  • @AfterReturning:在目标方法成功执行后执行通知(返回通知)。可以获取目标方法的返回值。
  • @AfterThrowing:在目标方法抛出异常后执行通知(异常通知)。可以获取抛出的异常信息。
  • @Around:在目标方法执行前后执行通知(环绕通知)。可以控制目标方法的执行流程和结果。
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethod() {}

    @Before("serviceMethod()")
    public void before(JoinPoint joinPoint) {
        System.out.println("执行前置通知(@Before)");
    }

    @After("execution(public * com.example.MyService.*(..))")
    public void afterMethod() {
        System.out.println("执行后置通知(@After)");
    }

    @AfterReturning(pointcut = "execution(public * com.example.MyService.*(..))", returning = "result")
    public void afterReturningMethod(Object result) {
        System.out.println("执行返回通知(@AfterReturning),返回值:" + result);
    }

    @AfterThrowing(pointcut = "execution(public * com.example.MyService.*(..))", throwing = "exception")
    public void afterThrowingMethod(Exception exception) {
        System.out.println("执行异常通知(@AfterThrowing),异常信息:" + exception.getMessage());
    }

    @Around("execution(public * com.example.MyService.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("执行环绕通知前(@Around)");
        
        Object result = joinPoint.proceed(); // 执行目标方法
        
        System.out.println("执行环绕通知后(@Around)");
        
        return result;
    }
}

在上述示例中,我们使用了 @Aspect 注解将 MyAspect 类标记为切面类,并分别使用了 @Before、@After、@AfterReturning、@AfterThrowing 和 @Around 注解定义了不同类型的通知。

当目标类 com.example.MyService 的方法被调用时,AOP 将根据注解的定义,在对应的切点上触发相应的通知方法。这些通知方法可以根据业务需求执行额外的操作,例如日志记录、性能监控、事务处理等。

需要注意的是,切面类需要被 Spring 容器扫描并纳入管理,因此在切面类上通常会标记 @Component 注解。另外,还需要在 Spring Boot 的配置文件中开启 AOP 功能(例如 @EnableAspectJAutoProxy 注解)才能正常使用 AOP。

aop中的advice通知有哪些入参

在 AOP 中,不同类型的通知(Advice)具有不同的入参。下面是各种通知的入参区别:

  • @Before 前置通知:

入参:JoinPoint,表示当前拦截的连接点(方法执行),可以获取目标方法的信息。

  • @AfterReturning 返回通知:

入参:JoinPoint,表示当前拦截的连接点(方法执行),可以获取目标方法的信息。
入参:Object returnValue,表示目标方法的返回值。

  • @AfterThrowing 异常通知:

入参:JoinPoint,表示当前拦截的连接点(方法执行),可以获取目标方法的信息。
入参:Throwable exception,表示抛出的异常对象。

  • @After 后置通知:

入参:JoinPoint,表示当前拦截的连接点(方法执行),可以获取目标方法的信息。

  • @Around 环绕通知:

入参:ProceedingJoinPoint,表示可执行目标方法的连接点(方法执行),可以手动控制目标方法的执行时机。
返回值:目标方法的返回值。

在上述入参中,JoinPoint 提供了很多有用的方法,例如 getSignature() 获取方法签名、getArgs() 获取方法参数等。ProceedingJoinPoint 继承自 JoinPoint,并额外提供了 proceed() 方法,用于手动执行目标方法。

需要注意的是,通知的入参可以根据需要灵活地进行调整,你可以根据业务需求选择合适的入参类型。另外,通知方法可以使用多个入参,也可以不使用任何入参。具体使用哪些入参取决于你的业务逻辑和需求。

ProceedingJoinPoint 常用哪些方法

  • ProceedingJoinPoint extends JoinPoint 接口,是在使用 AspectJ 或者 Spring AOP 时,用于表示方法调用的连接点。它提供了以下常用方法:

  • Object[] getArgs(): 获取方法参数的数组。

  • Signature getSignature(): 获取被代理方法的签名,可以通过该对象获取方法的名称、声明类型等信息。

  • Object getTarget(): 获取被代理的目标对象。

  • Object getThis(): 获取当前代理对象。

  • void set$AroundClosure(AroundClosure arc) throws Throwable: 在拦截方法执行时,可以将一个自定义的环绕通知传递给目标方法执行,并且在该环绕通知中可以控制是否执行目标方法以及修改方法的返回值。

  • Object proceed(Object[] args) throws Throwable: 执行目标方法,传入新的参数,并将按照原始的调用顺序继续执行切面和目标方法。

  • Object proceed() throws Throwable: 执行目标方法,无需传入新的参数,并将按照原始的调用顺序继续执行切面和目标方法。

  • 这些方法可以在编写切面时使用,用于对目标方法进行操作、调用和控制流程。例如,你可以使用 getArgs() 方法获取方法的参数值数组,使用 getSignature() 方法获取方法的签名,通过 proceed() 方法继续执行目标方法等。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @Around("execution(public * com.example.MyService.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        String methodName = joinPoint.getSignature().getName();
        
        // 获取目标对象
        Object target = joinPoint.getTarget();
        
        // 获取当前代理对象
        Object proxy = joinPoint.getThis();
        
        // 获取方法参数值
        Object[] args = joinPoint.getArgs();
        
        // 输出方法调用信息
        System.out.println("方法名:" + methodName);
        System.out.println("目标对象:" + target);
        System.out.println("代理对象:" + proxy);
        System.out.println("参数值:" + Arrays.toString(args));
        
        // 执行目标方法并获取返回值
        Object result = joinPoint.proceed();
        
        // 修改返回值
        if (result instanceof String) {
            result = ((String) result).toUpperCase();
        }
        
        // 返回修改后的返回值
        return result;
    }
}

回顾:
本文介绍了AOP的常用注解和常用入参, 在使用AOP注解时,需要先声明启用切面编程即@EnableAspectJAutoProxy,aop中可以有的入参,最重要的是ProceedingJoinPoint 入参,该入参有较多的方法可以获取到很多内容,下一章介绍AOP的应用,自定义注解。

posted @ 2023-10-19 09:53  kisshappyboy  阅读(22)  评论(0编辑  收藏  举报