Springboot实战 Aop

78 阅读2分钟

1. 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 创建测试用controller

@RestController
@RequestMapping("/user")
public class LoginController {

    @RequestMapping("/login")
    public void login() {

    }
}

3. 创建aop

3.1 创建切面类

@Slf4j
@Aspect
@Component
public class Log {

aop 切面类由切点和通知组成。

3.2 创建切点

@Pointcut("execution(* com.example.demo2.authorize.controller.*.*(..))")
public void info() {
}

切点是通过@Pointcut注解和切点表达式定义的。

@Pointcut注解可以在一个切面内定义可重用的切点。

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如图是execution表达式的语法:

execution表示在方法执行的时候触发。以“ ”开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,“ ”可以表示任意类和任意方法。对于方法参数列表,可以使用“..”表示参数为任意类型。如果需要多个表达式,可以使用“&&”、“||”和“!”完成与、或、非的操作。 如下图:

QQ截图20231024113212.png

3.3 创建通知

通知有五种类型,分别是:

前置通知(@Before):在目标方法调用之前调用通知

后置通知(@After):在目标方法完成之后调用通知

环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法

返回通知(@AfterReturning):在目标方法成功执行之后调用通知

异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

代码中定义了三种类型的通知,使用@Before注解标识前置通知,打印“beforeAdvice...”,使用@After注解标识后置通知,打印“AfterAdvice...”,使用@Around注解标识环绕通知,在方法执行前和执行之后分别打印“before”和“after”。这样一个切面就定义好了,代码如下:

package com.example.demo2.authorize.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
public class Log {
    @Pointcut("execution(* com.example.demo2.authorize.controller.*.*(..))")
    public void info() {
        log.info("456");
    }

    @Before("info()")
    public void beforeAdvice() {
        System.out.println("beforeAdvice...");
    }

    @After("info()")
    public void afterAdvice() {
        System.out.println("afterAdvice...");
    }

    @Around("info()")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("aroundAdvice before");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable t) {
            t.printStackTrace();
        }
        System.out.println("aroundAdvice after");
    }
}

4. 测试

浏览器访问 127.0.0.1:8080/user/login

image.png

5 如果报错:

AopInvocationException:Null return value from advice

参考: juejin.cn/post/729318…