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表示在方法执行的时候触发。以“ ”开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,“ ”可以表示任意类和任意方法。对于方法参数列表,可以使用“..”表示参数为任意类型。如果需要多个表达式,可以使用“&&”、“||”和“!”完成与、或、非的操作。 如下图:
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
5 如果报错:
AopInvocationException:Null return value from advice