接上一篇文章,了解了AOP的概念之后,这篇文章实践一下AOP在项目中的使用。
我直接在原来的learning-demo项目里面使用AOP记录controller接口的日志
修改依赖
<dependencies>
<!-- Spring Boot AOP 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
修改好之后,用maven同步一下。
在项目已有的controller上实践AOP

上图就是项目中已有的获取所有用户的接口。
下面就是日志记录类,使用AOP。
和controller接口的目录位置。

@Pointcut注解 execution表达式,表示要拦截哪个controller,当前的表达式的意思是controller包下面的任意类的任意一个方法,使用任意参数,都会被拦截。

有4类通知:
- 前置通知:在目标方法执行之前执行
- around通知:控制目标方法的执行时机
- 返回通知:在目标方法执行完成返回结果之后,执行。
- 后置通知:无论目标方法执行成功与否,是否抛异常,都会执行。
前置通知
@Before("controllerPointcut()")
public void doBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.info("【前置通知】准备执行方法: {}, 传入的参数是: {}", methodName, Arrays.toString(args));
}
Around通知
@Around("controllerPointcut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
log.info("【环绕通知】目标方法执行前...");
// 显式调用 proceed() 让目标方法去执行
Object result = pjp.proceed();
long endTime = System.currentTimeMillis();
log.info("【环绕通知】目标方法执行后... 执行总耗时: {} 毫秒", (endTime - startTime));
return result; // 必须把返回值 return 出去,否则前端拿不到数据
}
返回通知
@AfterReturning(value = "controllerPointcut()", returning = "result")
public void doAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
log.info("【返回通知】方法 {} 执行完毕, 返回结果是: {}", methodName, result);
}
后置通知
@After("controllerPointcut()")
public void doAfter(JoinPoint joinPoint) {
log.info("【后置通知】方法 {} 最终结束", joinPoint.getSignature().getName());
}
}
代码写入和测试

代码写入到LoggingAspect.java。 运行一下。
趁着应用启动,先打开postman等着,奇怪的是,我用postman访问了一下接口,期待中的日志没有出现在终端上。我看看怎么回事。
好像是我aspect类的通知方法没有加注解的问题。我加上再试一下。
试了一下,果然如此。
为了Around通知明显一点,给接口加上500ms延迟。
测试一下:用获取全部用户的接口。

可以,四个通知都成功打印到终端了。
四个通知的执行顺序可以看出来是
- Around,before
- Before
- AfterReturning
- After
- Around,after
四类日志记录的顺序
@Around (开始) -> 拦截请求,准备计时
@Before -> 进入方法前
执行Controller 里的代码
@AfterReturning -> 拿到 Controller 的返回值
@After -> 最终收尾
@Around (结束) -> 计算总耗时,放行结果