1、简介
随着Spring框架的不断更新迭代,在面向切面编程中,Spring AOP使用 @Around(在方法执行前后) 、@Before(在方法执行前)、 @AfterReturning(未抛异常) 、 @After(不论是否抛异常) 、 @Around (在方法执行后)
2、注解描述
注解 | 描述 |
@Before | 在代理方法执行前执行 |
@After | 在代理方法执行后执行 |
@AfterReturning | 在代理方法执行返回后执行 |
@AfterThrowing | 在代理方法抛异常时执行 |
@Around | 包围着代理方法执行 |
@Pointcut | 定义切面 |
3、@Pointcut注解的使用
@Pointcut中可以指定execution表达式和其他例如args、within、target等表达式,execution 最为常用,其使用具体模式如下:
execution(<修饰符模式> <返回类型模式><方法名模式>(<参数模式>)<异常模式>)
# 返回类型模式、方法名模式和参数模式外,其它项都是可选的
# 示例:在com.test包及其子包下所有Controller中所有方法都是被代理的方法
@Pointcut("execution(public * com.test..*Controller.*(..))")
表达式中通配符的含义:
.. # 在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
* # 配任何数量字符(只能代表一个字符串,用在方法中代表一个任意类型参数)。
+ # 匹配指定类型的子类型;仅能作为后缀放在类型模式后边
4、通知注解使用@PointCut
4.1、定义连接点
@Pointcut("execution(public * com.weilong..*Controller.*(..))")
public void controllerPointcut(){}
4.2、通知注解关联连接点
@Before("controllerPointcut()")
@After("controllerPointcut()")
@Around("controllerPointcut()")
@AfterThrowing("controllerPointcut()")
@AfterReturning("controllerPointcut()")
5、测试通知注解执行顺序
5.1、准备测试类
5.1.1、切面类
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Modifier;
@Aspect
@Component
@Slf4j
public class LogAspect1 {
public LogAspect1(){
System.out.println("LogAspect");
}
// excution表达式标识符解释:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?) 返回类型模式、方法名模式和参数模式外,其它项都是可选的
// ..:在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
// *:匹配任何数量字符(只能代表一个字符串,用在方法中代表一个任意类型参数)。
@Pointcut("execution(public * com.test..*Controller.*(..))")
public void controllerPointcut(){
}
// 在sprintboot3中aop注解执行顺序:
// @Around (在方法执行前) -> @Before -> @AfterReturning(未抛异常) -> @After(不论是否抛异常) -> @@Around (在方法执行后)
@Before("controllerPointcut()")
public void doBefore(JoinPoint joinPoint){
log.info(" @Before...");
}
// ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中
@Around("controllerPointcut()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// Object proceed() throws Throwable //执行目标方法
// Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
log.info(" @Around...方法前");
Object result = proceedingJoinPoint.proceed();
log.info(" @Around...方法后");
return result;
}
@After("controllerPointcut()")
public void after(JoinPoint joinPoint){
log.info(" @After...");
}
@AfterThrowing("controllerPointcut()")
public void afterThrow(JoinPoint joinPoint){
log.info(" @AfterThrowing...");
}
@AfterReturning("controllerPointcut()")
public void afterReturn(JoinPoint joinPoint){
log.info(" @AfterReturning...");
}
}
5.1.2、Controller类
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping(value = "/hello")
public String test(){
//int i = 1 / 0; // 测试抛异常放开
return "hello world!";
}
}
5.2、代理方法未抛出异常
执行顺序如下:
5.3、代理方法抛出异常
执行顺序如下:
6、总结
本文详细介绍了Springboot3中aop在两种情况下通知的执行顺序,关于更多aop深入知识将在后续博文中更新。